We are all hopeful that there might be some cause for tentative optimism regarding the eventual end of coronavirus pandemic. But horror fan Adam B. has dug up a new side effect that may upend everything.
Many years ago, I worked for a company that mandated that information like user credentials should never be stored "as plain text". It had to be "encoded". One of the internally-developed HR applications interpreted this as "base64 is a kind of encoding", and stored usernames and passwords in base64 encoding.Steven recently encountered a… similar situation. Specifically, his company upgraded their ERP system, and reports that used to output taxpayer ID numbers now outputs ~201~201~210~203~… or similar values. He checked the data dictionary for the application, and saw that the taxpayer_id field stored "encrypted" values. Clearly, this data isn't really encrypted.Steven didn't have access to the front-end code that "decrypted" this data. The reports were written in SSRS, which allows Visual Basic to script extensions. So, with an understanding of what taxpayer IDs should look like, Steven was able to "fix" the reports by adding this function:
Pierre inherited a PHP application. The code is pretty standard stuff, for a long-living PHP application which has been touched by many developers with constantly shifting requirements. Which is to say, it's a bit of a mess.But there's one interesting quirk that shows up in the codebase. At some point, someone working on the project added a kinda stock way they chose to handle exceptions. Future developers saw that, didn't understand it, and copied it to just follow what appeared to be the "standard".And that's why so many catch blocks look like this:
At a certain point, it becomes difficult to write a unit test without also being able to provide mocked implementations of some of the code. But mocking well is its own art- it's easy to fall into the trap of writing overly complex mocks, or mocking the wrong piece of functionality, and ending up in situations where your tests end up spending more time testing their mocks than your actual code.Was Rhonda's predecessor thinking of any of those things when writing code? Were they aware of the challenges of writing useful mocks, of managing dependency injection? Or was this Java solution the best they could come up with:
Josh's company hired a contracting firm to develop an application. This project was initially specced for just a few months of effort, but requirements changed, scope changed, members of the development team changed jobs, new ones needed to be on-boarded. It stretched on for years.Even through all those changes, though, each new developer on the project followed the same coding standards and architectural principles as the original developers. Unfortunately, those standards were "meh, whatever, it compiled, right?"So, no, there weren't any tests. No, the code was not particularly readable or maintainable. No, there definitely weren't any comments, at least if you ignore the lines of code that were commented out in big blocks because someone didn't trust source control.But once the project was finished, the code was given back to Josh's team. "There you are," management said. "You support this now."Josh and the rest of his team had objections to this. Nothing about the code met their own internal standards for quality, and certainly it wasn't up to the standards specified in the contract."Well, yes," management replied, "but we've exhausted the budget.""Right, but they didn't deliver what the contract was for," the IT team replied."Well, yes, but it's a little late to bring that up.""That's literally your job. We'd fire a developer who handed us this code."Eventually, management caved on documentation. Things like "code quality" and "robust testing" weren't clearly specified in the contract, and there was too much wiggle room to say, "We robustly tested it, you didn't say automated tests." But documentation was listed in the deliverables, and was quite clearly absent. So management pushed back: "We need documentation." The contractor pushed back in turn: "We need money."Eventually, Josh's company had to spend more money to get the documentation added to the final product. It was not a trivial sum, as it was a large piece of software, and would take a large number of billable hours to fully document.This was the result:
When you look at bad code, there's a part of your body that reacts to it. You can just feel it, in your spleen. This is code you don't want to maintain. This is code you don't want to see in your code base.Sometimes, you get that reaction to code, and then you think about the code, and say: "Well, it's not that bad," but your spleen still throbs, because you know if you had to maintain this code, it'd be constant, low-level pain. Maybe you ignore your spleen, because hey, a quick glance, it doesn't seem that bad.But your spleen knows. A line that seems bad, but mostly harmless, can suddenly unfurl into something far, far nastier.This example, from Rikki, demonstrates:
Universally Unique Identifiers are a very practical solution to unique IDs. With 10^30 possible values, the odds of having a collision are, well, astronomical. They're fast enough to generate, random enough to be unique, and there are so many of them that- well, they may not be universally unique through all time, but they're certainly unique enough.Right?Krysk's predecessor isn't so confident.
After reading through so many of your submissions these last few weeks,I'm beginning to notice certain patterns emerging. One of these patterns isthat despite the fact that dates are literally as old as time, people seem pathologically prone to bungling them. Surely our readers are already familiar with the notable "Falsehoods Programmers Believe" series of blog posts, but if you happen somehow to have been living under an Internet rock (or a cabbage leaf) for the last few decades, you might start your time travails at Infinite Undo.The examples here are not the most egregious ever (there are better coming later or sooner) but they are today's:Famished Dug S. peckishly pronounces "It's about time!"
Steven was working on a temp contract for a government contractor, developing extensions to an ERP system. That ERP system was developed by whatever warm bodies happened to be handy, which meant the last "tech lead" was a junior developer who had no supervision, and before that it was a temp who was only budgeted to spend 2 hours a week on that project.This meant that it was a great deal of spaghetti code, mashed together with a lot of special-case logic, and attempts to have some sort of organization even if that organization made no sense. Which is why, for example, all of the global constants for the application were required to be in a class Constants.Of course, when you put a big pile of otherwise unrelated things in one place, you get some surprising results. Like this:
When Andy inherited some C# code from a contracting firm, he gave it a quick skim. He saw a bunch of methods with names like IsAvailable or CanPerform…, but he also saw that it was essentially random as to whether or not these methods returned bool or string.That didn't seem like a good thing, so he started to take a deeper look, and that's when he found this.
Writing code that is reusable is an important part of software development. In a way, we're not simply solving the problem at hand, but we're building tools we can use to solve similar problems in the future. Now, that's also a risk: premature abstraction is its own source of WTFs.Daniel's peer wrote some JavaScript which is used for manipulating form inputs on customer contact forms. You know the sorts of forms: give us your full name, phone number, company name, email, and someone from our team will be in touch. This developer wrote the script, and offered it to clients to enhance their forms. Well, there was one problem: this script would get embedded in customer contact forms, but not all customer contact forms use the same conventions for how they name their fields.There's an easy solution for that, involving parameterizing the code or adding a configuration step. There's a hard solution, where you build a heuristic that works for most forms. Then there's this solution, which… well…. Let me present the logic for handling just one field type, unredacted or elided.
Today's Error'd submissions are not so much WTF as simply "TF?" Please try to explain the thought process in the comments, if you can.Plaid-hat hacker Mark writes "Just came across this for a Microsoft Security portal.Still trying to figure it out." Me, I just want to know what happens when you click "Audio".
Chuck had some perfectly acceptable C# code running in production. There was nothing terrible about it. It may not be the absolute "best" way to build this logic in terms of being easy to change and maintain in the future, but nothing about it is WTF-y.
Code, like anything else, ages with time. Each minor change we make to a piece of already-in-use software speeds up that process. And while a piece of software can be running for decades unchanged, its utility will still decline over time, as its user interface becomes more distant from common practices, as the requirements drift from their intent, and people forget what the original purpose of certain features even was.Code ages, but some code is born with an expiration date.For example, at Jose's company, each year is assigned a letter label. The reasons are obscure, and rooted in somebody's project planning process, but the year 2000 was "A". The year 2001 was "B", and so on. 2025 would be "Z", and then 2026 would roll back over to "A".At least, that's what the requirement was. What was implemented was a bit different.
Today's code is only part of the WTF. The code is bad, it's incorrect, but the mistake is simple and easy to make.Lowell was recently digging into a broken feature in a legacy C application. The specific error was a failure when invoking a sed command from inside the application.
Many years ago, Kari got a job at one of those small companies that lives in the shadow of a university. It was founded by graduates of that university, mostly recruited from that university, and the CEO was a fixture at alumni events.Kari was a rare hire not from that university, but she knew the school had a reputation for having an excellent software engineering program. She was prepared to be a little behind her fellow employees, skills-wise, but looked forward to catching up.Kari was unprepared for the kind of code quality these developers produced.First, let's take a look at how they, as a company standard, leveraged C++ templates. C++ templates are similar (though more complicated) than the generics you find in other languages. Defining a method like void myfunction<T>(T param) creates a function which can be applied to any type, so myfunction(5) and myfunction("a string") and myfunction(someClassVariable) are all valid. The beauty, of course, is that you can write a template method once, but use it in many ways.Kari provided some generic examples of how her employer leveraged this feature, to give us a sense of what the codebase was like:
“Some people,” said the sage, “are lucky enough to also have a completely separate environment for production.” Today's nuggets of web joy are pudding-proof. Hypothetically hypochondriac STUDENTS[$RANDOM] gasped “I tried to look up information about Covid tests at the institution. Instead I found…this.”
Totally Fungible Tokens NFTs, or non-fungible tokens, are an exciting new application of Blockchain technology that allows us to burn down a rainforest every time we want to trade a string representing an artist's signature on a creative work. Many folks are eagerly turning JPGs, text files, and even Tweets into NFTs, but since not all of us have a convenient rainforest to destroy, The Daily WTF is happy to offer at alternative, the Totally Fungible Token What Is a Totally Fungible Token? A TFT is a unique identifier which we can generate for any file or group of files. It combines the actual data in the file(s) with a Universally Unique Identifier, and then condenses that data using a SHA-256 hashing algorithm. This guarantees that you have a unique token which represents that you have created a unique token for that data. How is this better than an NFT? There are a few key advantages that TFTs offer. First, they're computationally very cheap to make, allowing even a relatively underpowered computer participate actively in the token ecosystem. In addition, this breaks all dependencies on the blockchain, meaning that you don't need to use or spend cryptocurrency to create, purchase, or trade these tokens. Most important: much like NFTs, a TFT is absolutely worthless, but we're not promoting these as some sort of arcane investment instrument, so there won't be any sort of bubble. The value of your TFT will remain essentially zero, for the entire life of your TFT. There is no volatility. In the interests of efficiency, this also performs terribly on large files. How big is too big? That depends on your browser! Enjoy finding out what's too big to encode! Generate a TFT Use the button below to browse for a file on your computer, and this will generate a unique token showing that you generated a unique token. Feel free to share, sell, or trade these tokens with your friends! No information about your files is in the token, so it's guaranteed to be completely meaningless! Give it away, sell it, just write it down on a napkin, your TFT is yours to use as you please! Token: Grab the source and tweak the algorithm yourself!. Also, for convenience, there's a dedicated TFT page which, long term, is probably a better tool than this article, since you'll be wanting to play with TFTs for a long time yet, I imagine.Potential optimizations include: streaming the file conversion so we don't have to have the whole thing in memory, or just replacing all of this with a random number, which would likely be just as good.The TFT for the tft generator code is tft.js;dbbbf23d24502dba96913f18fa031203977b48db090a4a52ff6258a2c3bceecc, so enjoy! [Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.
Query strings are, as the name implies, strings. Now, pretty much any web application framework is going to give you convenient access to the query string as a dictionary or map, because at the end of the day, it is just key/value pairs.But what's the fun in that? Glen's application needed to handle query strings in the form: zones=[pnw,apac]&account_id=55. Now, enclosing the list in square brackets is a little odd, but actually makes sense when you see how they parse this:
There are often two types of software development departments mentioned: the kind where software is the product, and the kind where software enhances or sells the product. ChemCo is a third type: a physical chemistry lab, one with extensive customization of lab setups and computer-controlled devices that need to be programmed, as well as a need for statistics and simulations to handle the results. The team includes one C/LabVIEW magician, one Octave specialist, one Java developer, and one Python scripter. Therefore, most of the computer-controlled setups have LabVIEW GUIs and C DLLs for the logic, though some have Python over top of the DLLs instead.The year is 2016, and ChemCo has just bought a new signal generator. The team's newest engineer, one who knows only Perl, Octave, and R, is tasked with writing a DLL that can be called from their LabView application to control the generator. Faced with learning either C or C++, he chooses C because "the K&R is less than 300 pages while Prata has more than 1200."The device speaks SCPI, but since ChemCo has a real problem with Not Invented Here syndrome, the new guy writes the library from scratch. During the period that follows, he discovers:
No loops, no branches, barely a pun and almost free of alliteration.Big-box shopper Worf discovers"This Chromebook's screensaver crash might be Truth In Advertising."
Dan was reviewing some PHP code written by a co-worker, as part of taking on a project. The code was in “support” mode, rarely receiving changes, getting bug fixes only when absolutely necessary, and nobody really wanted to be the person responsible for it.One of those “not absolutely necessary” bugs was that sometimes, it just didn’t save data. The user would enter a product listing, hit save, get a success message back, but the listing wouldn’t actually be saved. No one had really dug into it, because having the end user do double data entry didn’t bother anyone but the end user.While thinking about that, Dan found this:
Imagine, if you will, that you see a method called FileExists. It takes a string input called strPath, and returns a bool. Without looking at the implementation, I think you'd have a very good sense of what it's supposed to do. Why, you wouldn't even expect much documentation, because the name and parameters are really clear about what the method actually does.Unless this method was in the C# codebase "AK" inherited. In that case, the behavior of FileExists might surprise you:
User experience, and its related topic of user interface design, are important. How important? Well the US government’s General Service Administration (GSA) took the time to build a website to explain what it is. What other proof do we need? Well not only did the GSA build a website, but they invested in the SEO necessary to make it top of Google organic search, right below the featured snippet from interaction-design.org. Which is why the saga and ongoing story of Citibank’s debt repayment blunder all the more amazing. Here’s a quick recap:
Today's Error'd submissions all center around another common pitfall of the modern web application: failed text substitutions and the ensuing unintentional hilarity.Antipodean Tony B. sends a Scot sir slur, writing "The mighty Beeb dumbs it down?"
Jaco was adding some caching to a Java application. Quite wisely, Jaco wrote plenty of tests around his change, ran the test suite, and confirmed everything was green. It ran fine in testing, but when it went to production, everything failed.Well, as it turned out, the configuration for the production environment loaded slightly different Java classes. One of those "only-loaded-in-production" modules did this:
One of the powers of structured exception handling is that it lets you define your own exception types. That's useful, as your code can communicate a lot of information about what's gone wrong when you use your own custom exceptions.But sometimes, the custom exception type leaves us asking more questions. Christophe found this Java code from a "big application for a big company".
Sometimes, it really is the comment which makes the code. Sometimes, the comments make simple (but still more complex than it needs to be) code less clear.For example, Thomas provides this code, and comment, which… I understand what is happening here, despite the comment:
Everyone likes getting a pay raise. Well, I suppose it depends on why. And HR isn't going to be too happy about your raise if it comes as the result of an easy-to-avoid software bug.Cédric V's company makes payroll software mostly used in and around France. One of their customers had a problem: when paying employees, it would give them a significant raise- sometimes by two orders of magnitude, rarely by three or four.What was surprising is that this happened to one customer, but none of their other customers. They couldn't replicate it on their test environment either. But once Cédric started digging into the code, it wasn't hard to understand what the root cause was.
It's hard to define what makes today's batch of submissions so special. Is it just the futility? Or is it the certainty that nobody nowhere knows nothing?Audiophile Neal S. tentatively asserts "Not sure this is where the lyrics are supposed to be on the Spotify UI."
Ulvhamne works on a team with over a hundred other developers. It's a big group, working on a huge project. And some of the quality in that code base gets… variable. Worse, when a bug pops up, it can be tricky to even identify what in the code is triggering the bug, let alone what the root cause is.For example, one of the config-file fields needed a number to specify the beginning and end of a range. If you put in a relatively short range- thousands or hundreds of values- everything worked fine. That was a pretty typical use case. But if you put in something closer to MAX_INT, everything worked fine for a little bit, but within moments the server would grind to a halt, memory would fill up, and the OS would hang as it ended up constantly thrashing pages to disk.Ulvhamne joked with one of his co-workers. "Wouldn't it be funny if, instead of just tracking the range's endpoints, they populated an array with all the possible values instead?"
Like the war between Emacs and Vim, developers also tend to wage a war between "strongly typed" and "loosely typed" languages. There are tradeoffs either way, and I think that's why you see things like TypeScript and Python's type annotations starting to creep into loosely typed languages- types when you need them, but not required. But if you're not comfortable with types, and don't really understand type casting, you might start writing some code like, well, like these examples.Sashi found this C# code:
Like the war between Emacs and Vim, developers also tend to wage a war between "strongly typed" and "loosely typed" languages. There are tradeoffs either way, and I think that's why you see things like TypeScript and Python's type annotations starting to creep into loosely typed languages- types when you need them, but not required. But if you're not comfortable with types, and don't really understand type casting, you might start writing some code like, well, like these examples.Sashi found this C# code:
We have a lot of stories about the code coming from offshore/outsourced developers being of low quality. Today, Radu S sends us the reverse. He used to work for one of those offshore development shops. A customer started development in-house, and then decided that they didn't want to support their own code anymore, and shipped it off to Radu's company.This block represents what he's working with:
A lesson that everyone learns at some point is "don't write your own authentication code." Authentication, like encryption, and like dates, is incredibly complex and has all sorts of ways you can subtly mess it up and not realize your mistake.Take, for example, this code from Christopher. His peer wrote this code, added a single test record to the database, saw that it worked, and called it a day.
There are many ways to debug your code. You might use an actual graphical debugger, wrestle with GDB, just spam print statements, or rely on a logging framework to help you generate useful diagnostic output.Since you're going to need some logging output no matter what, it's always good to heavily instrument your code. Using logging levels, you can control quite well what gets dumped when. Well, "LostLozz" had a co-worker who found an… interesting way to control logging.
"I was once working for a company that primarily dealt with Oracle products," Tai writes.That vendor, who shall not be named again, provided an installer. Tai ran it, and it failed. Since the installer was a shell script, she opened up the file and took a look.
If you browse the Errords, it's easy to see that "giving customers a discount" is apparently harder than it looks.Brian's company had one of those "discounts are hard" problems, way back when. Sometimes instead of a discount reducing the price, it would raise it. The root cause was that the sales team setting up the promotions weren't clear about whether the discount amount should be a negative or positive number. Instead of adding validation to ensure they always entered a negative (or at least, a zero amount), one of Brian's predecessors fixed the bug in their C# like this:
George had gotten a new job as a contractor at a medium-sized book distributor. He arrived nice and early on Day 1, enthusiastic about a fresh start in a new industry.His "office" turned out to be a huge warehouse stacked high with books. Upon greeting him, his manager pointed him to a PC in the corner of the warehouse, sitting on a desk with no partitions around it. The manager leaned over the machine and made a few double-clicks with the mouse until he opened up the H: drive. "There you go," he muttered, then left.George stared after him, perplexed, wondering if the manager intended to bring over coffee or other coworkers to meet him. The way he was walking, though, seemed to convey that he had more important things to be doing than coddling greenhorns."You must be George. Hi, I'm Wally." Another gentleman came over with his hand poised to shake. "I handle the software we use to track inventory. Let me show you the ropes."Wally used the nearby computer to demonstrate a handful of the 200-odd Delphi forms that constituted the inventory application. The source code was not in any kind of source control; it was all in a folder named Wally on the shared H: drive. They were using a version of Delphi from 1995 ... in 2010. Their database was some vague, off-brand SQL-esque construct that George later learned had been dropped from support as of 2003.None of this inspired George's confidence, but he had a job to learn. Stifling a sigh, he asked Wally, "Could I have a copy of your database creation script? Then I could start with a fresh and empty database to learn on.""No problem. Come with me."Wally led George to another part of the warehouse where a different computer was set up; presumably, this was Wally's desk. Wally sat down at the machine and began typing away while tapping his foot and whistling a little tune.This went on, and on ... and on. It certainly didn't seem like the quick typing one would do to create an email with an attachment. George shifted his weight uneasily from one foot to the other. As the rhythmic typing and whistling continued, it hit him: Wally was typing out the entire CREATE DATABASE code—from memory.It took Wally a good 25 minutes to bang out everything needed to define 60-odd database fields including Title, ISBN, ISBN-19, Author, Publisher, etc. Finally, the one-man concert ceased; Wally sent the email. With a perfectly normal look on his face, he faced George and said, "There it is!"In the moment, George was too flabbergasted to question what he'd witnessed. Later, he confirmed that Wally had never even thought to have a saved CREATE DATABASE SQL script on hand. Sadly, this was far from the last point of contention he experienced with his coworker. Wally could not comprehend why George might want some general utility functions, or a clean interface between modules, or anything more advanced than what one found in chintzy programming manuals. George's attempts at process improvement and sanity introduction got his building access card invalidated one morning about a month after starting. No one had expressed any sort of warning or reproach to him beforehand. George was simply out, and had to move on.Move on he did ... but every once in a while, George revisits their old website to see if they're still in business. At the moment, said website has an invalid certificate. For a company whose whole business came down to head-scratching practices heaped upon 15 year-old unsupported tools, it's not so surprising. [Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!
Powers of two are second nature to a lot of programmers. They're nearly inescapable.Equally inescapable are programmers finding new ways to do simple things wrong. Take Sander's co-worker, who needed to figure out, given a number of bits, what's the largest possible value you could store in that number of bits. You or I might reach for our language's pow function, but boy, in C++, that might mean you need to add an include file, and that sounds hard, so let's do this instead:
Progress bars and throbbers are, in theory, tools that let your user know that a process is working. It's important to provide feedback when your program needs to do some long-running task.Hegel inherited a rather old application, written in early versions of VB.Net. When you kicked off a long running process, it would update the status bar with a little animation, cycling from ".", to "..", to "...".