by Remy Porter on (#64D3C)
If there's one thing worse in code than magic numbers, it's magic strings. Sean inherited an antique Visual C++ application, and the previous developers were very careful to make sure every string was a named constant.
|
The Daily WTF
Link | http://thedailywtf.com/ |
Feed | http://syndication.thedailywtf.com/TheDailyWtf |
Updated | 2024-11-21 18:16 |
by Remy Porter on (#64BTV)
As a general rule of thumb, when you see a class called StringConverter you know something is going to be wrong in there. That's at least what Erik thought when examining a bug in a totally different section of string handling code that just happened to depend on StringConverter.StringConverter might sound like some sort of utility belt class with a huge pile of methods in it, but no- it's only got two. So we should take a look at both.Let's start with the method called Escape.
|
by Jane Bailey on (#64BH2)
Ah, routers. The one piece of networking hardware that seems inescapable; even the most tech-illiterate among us needs to interface with their router at least once, to set up their home network so they can access the internet. Router technology has changed a lot over the years, including how you interface with the admin portal: instead of having to navigate to a specific IP address, some of them have you navigate to a URL that is intercepted by the router and redirected to the admin interface, making it easier for laymen to recall. But routers have their share of odd problems. I recently had to buy a new one because the one I was using was incompatible with my company's VPN for cryptic reasons even helpdesk had no real understanding of.Today's submission concerns a Vodafone router. Our submitter was setting up a network for a friend, and to make things easier, they set up a low-security password initially so they could type it repeatedly without worrying about messing it up. Once the network was set up, however, they wanted to change it to something long and cryptic to prevent against brute-force attacks. They generated a password like 6Y9^}Ky.SK50ZR84.p,5u$380(G;m;bI%NZG%zHd?lOStqRzS}Z?t;8qSg;[gy@ and plugged it in, only to be told it was a "weak" password.What? Length and variance both seem quite sufficient for the task—after all, it's not like there's roving bands of street gangs hacking into everyone's wifi routers and mucking about with the settings. There's no need for 300-character passwords.Curious, our submitter opened the Javascript source for the change password page to see what checks they failed, since the UI wasn't helping much:
|
by Lyle Seaman on (#648N8)
... or maybe oneth things snecod,as it turns out.This week, two unique anonymeesehave brought something to share, and our alienfriend Skippy piles on to the Lenovo laugh-in. Guten Morgen!Decisive Michael R. is flummoxed by the law of the excluded middle."YES," he assures us, "yes, those were checkboxes. And, no, not radios."
|
by Remy Porter on (#646EA)
Tina needs to write some software that integrates with a hardware device. Thatdevice controls access via behind a PIN, and thus Tina's team needs to track the valid PIN, so that they can, via software, update or alter the PIN.There's just one problem. That device has some opinions about how a Personal Identification Number should be represented:
|
by Remy Porter on (#6452F)
Picking random items without repetition is its own special challenge. It's one of those things that's not actually hard, but some programmers have a difficult time coming up with solutions to the problem. Abraham has found these two examples in some code he maintains:
|
by Remy Porter on (#643MM)
A large company with facilities all over the Asia-Pacific region opted to modernize. They'd just finished a pile of internal development that extended the functionality of a 3rd party package, and they wanted to containerize the whole shebang.That's where Fred came in, about 9 months into a 12 month effort. Things hadn't gone well, but a lot of the struggles were growing pains. Many of the containers were built as gigantic monoliths. A lot of the settings you might need to do a Kubernetes deployment weren't properly configured. It was a mess, but it wasn't a WTF, just a lot of work.The efforts of building the containerized, K8s deployments changed the company culture. The new rule was "container all the things", and all the things got containerized. Management was happy to be checking off new buzzwords, and the IT team was happy to have any sort of organization or process around deployments and their environment, since prior to this effort it was a lot of "copy this folder to this server, reboot, and cross your fingers".Everyone was happy, except for one team, led by Harry. "Your containers broke our software," Harry complained. Now, it wasn't "their" software- it was a purchased product. And like many enterprise software packages, it was licensed. That license was enforced via a smart card and a USB dongle.Which created a problem. Kubernetes is entirely about running your code absolutely abstracted from the physical hardware it's actually on. The USB dongle requires the code to be running on a specific physical device. The solution to the problem was obvious and simple: don't manage this one product via Kubernetes.But that wasn't an option. "We use Kubernetes to manage all of our deployments," management said. One of the managers helpfully linked to an interview in a trade magazine where the CTO cheerily shared the benefits of Kubernetes."Right, but this particular product is ill-suited to that kind of deployment," Fred and his team countered."Okay, yes, but we use Kubernetes for all of our deployments."And, as of this writing, that's where things sit. Everything must be containerized and hosted in Kubernetes. One software product doesn't play nice in that environment, but it must be wedged into that environment. Currently, the product lives on the same private server it used to live on, but this is a "stopgap" until "a solution is found". Officially it's out of compliance with company standards, and shows up as an evil red light on all the IT dashboards. [Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!
|
by Remy Porter on (#642A1)
"Never trust your inputs" is a generally good piece of advice for software development. We can, however, get carried away.Janice inherited a system which, among many other things, stores phone numbers. Like most such systems, the database validates phone numbers, and guarantees that numbers are stored in a canonical format, as text.For some reason, their Rails presentation layer isn't satisfied with this, and needs to validate the data coming from the database. In their specific environment, they know the database only contains canonical phone numbers, but honestly, I'm willing to forgive the belts-and-braces approach, as I've certainly used enough databases that couldn't provide those kinds of guarantees.No, the problem is the way they went about it.
|
by Lyle Seaman on (#63ZAH)
I know that I recently implied a fondness for cookedcorvid, but if this keeps up I'm going to turn vegan. Itwill be a sad day if I have to turn in the barnyard puns.ReaderRuthless R. goes in HAM, crowing"Daily WTF goes WTF with its RSS Feed." It's getting to be less funny.
|
by Remy Porter on (#63XY2)
Caleb (previously) continues to work for a vehicle finance company. Most recnetly, he was working on a data ingestion application. Its job was to pull in a big ol' pile of CSVs from a mix of vendors and customers and feed it into a central database to keep things up to date."Application", however, is misleading. In reality, it was a suite of Access databases scattered around various network shares. Each represented a custom data loading pathway for a kind of data. It wasn't true that each was isolated from every other- frequently, the data flow would be "Open database \\fileserver\processing\vendor01.mdb, use the form to load the CSV file, then open \\fileserver\processing\process01.mdb, but only AFTER you've deleted the CSV file."Caleb's job was "easy": trawl through this thicket and figure out which parts handled just vehicle model information, sourced from vehicle manufacturers. Figure out what it did, and then reimplement in something that wasn't a fragile pile of Access databases.While working on that, a new problem appeared: manufacturers were announcing their 2023 model numbers, but the system simply couldn't ingest those. No vehicles with 2023 model numbers could be created. After searching for awhile, Caleb figured out that it went through this table, created in 2008, which hadn't had any data added/removed since:ModelYearAbbrModelYear420045200562006720078200892009102010112011122012132013142014152015162016172017182018192019202020212021Now, this isn't particularly shocking, and honestly, probably wasn't even a terrible idea. It's just that, since new years were never added, it made it impossible to add vehicles in the 2023 model year.But that still left Caleb with another question: their system had vehicles with a 2022 model year just fine. Did a bug let the data load last time? Is there another code pathway Caleb hasn't found? Is there a mystery Access database on a file share no one remembers that can handle model years more recent than 2021? No one knows, and truly, does anyone want to know? Down that path lies an eldritch madness, a cosmic horror that would cause our very souls to bleed.(Or, probably, someone just manually inputted all that data, but the eldritch thing is more fun.) [Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!
|
by Remy Porter on (#63WSN)
Penny uses a Python ORM. Like most ORMs, it involves a lot of "inherit from a BaseModel class, and get all your database access stuff for "free". Or at least, it used to. They've released an update.
|
by Remy Porter on (#63V2M)
Yesterday, I briefly mentioned the "TODO" comment as part of the WTF. Anyone who develops software for long enough is going to develop some pet peeves. Lord knows, my feelings on Hungarian Notation are well established. Or ternaries, though honestly, for ternaries, I mostly am in it for the puns.But, I've got another pet peeve that's crawling up my butt far enough that I felt the need to do a soapbox about it.
|
by Remy Porter on (#63ST9)
Robert has inherited a .NET application. It's a big-ball-of-mud, full of monstrous classes of thousands of lines and no coherent purpose, complete with twenty constructors.It's ugly and messy, but it's mostly just generically bad. This method, however, is a lot of bad choices in very few lines.
|
by Lyle Seaman on (#63Q1F)
In case anyone is wondering "is there anything so lame that it's not evengood enough to get published by Error'd", the answer is yes. There is acategory of submissions that is very common, but in the completely capricious opinion of this editor, just not very funny. That category is clearly broken listings on amazon.com. We usually get two or three of theseevery week. We save them up, and maybe someday the news will be so slow that we have no choice but to run an entire column of nothing but Amazon bloopers. This week was no different from the usual, except that this timethe September stress has struck a nerve and so you get to see what the brink of madness looks like from the inside.Tippler Matthias poured one out for us. "Seems someone already tried some of the good stuff while uploading the images to Amazons catalog."
|
by Remy Porter on (#63NE0)
Initech was the big customer for Chops's company. And like a lot of big customers, they had requests and they had the weight to throw around to get their requests fulfilled. When they wanted a new feature, they got a new feature. When they found a bug, they got the patch ASAP.No matter how special Initech thought they were, they were mostly requesting things that other customers wanted anyway, so it worked pretty well.So, one day, they submitted a pile of feature requests, the dev team got to work, and cranked out the features. They tested it, they shipped betas out to the customer, the customer liked the changes, confirmed that it passed user-acceptance, and was ready to deploy. Well, almost ready. There was one tiny little problem."So, we can't do this upgrade," said Jerry, the lead from Initech. "It violates our IT policy.""Um, how?" Chops asked."Well, the current approved version in our environment is 3.4.24. The version you're shipping us is 3.5.1. That's too big a version number change.""Oh, uh… we shipped 3.5 a few months ago…""Right, but we haven't gotten that approved. Can you add these features to the 3.4 version?"That request got escalated up to management, and since Initech was a big customer, management said, "Yes, absolutely, do it."The result was a disaster. While 3.5 and 3.4 were basically the same from the end user's perspective, a lot of internals had changed. The new features used the new internals, and when trying to backport them it was a lot of work. They started from the codebase of 3.4.30 (the last release of 3.4.x), and ended up breaking everything. Tests which passed under 3.5 started failing, tests which had been passing under 3.4 also started failing. No one was exactly sure how to backport these features to the old internals and it was eating a lot of developer cycles.Chops watched this slow motion disaster, and watched management getting increasingly upset. Initech wanted their new features, and they wanted them last week. So Chops decided to take matters into their own hands. They took the 3.5.1 build, and re-set the version numbers to be 3.4.31."Hey, Jerry," Chops said. "I've taken the latest version, 3.5.1, and I've renamed it 3.4.31. So the official version number is 3.4.31. Is that okay?""Uh, the version you're giving me is 3.4?""That's the version number on the file, yes. But the code is actually 3.5.""But the file says 3.4?""It does," Chops said. "And the 'about' information will also say 3.4.31.""Perfect, that'll do."Chops sent the file over. Jerry ran it through all their tests and confirmed it was still satisfactory. Initech's management confirmed that the version number only incremented a small amount, and it was still "officially" a 3.4 version.Everyone was happy with this outcome. [Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!
|
by Remy Porter on (#63M43)
Embedded chip documentation is sometimes very bad, and very confusing. Frequently it's difficult to really understand the ins and outs of a given chip without simply getting experience.Which is why Mr. Scrith was a bit surprised with this code, which came from someone who definitely should have known better.This code is for a "walking 1s" memory test- it simply visits every address in memory and writes a "1" and confirms that it can read back that "1". Such a test poses an interesting challenge: you can't use any variables, because they will live in RAM somewhere, so you need to limit yourself only to the registers exposed by your CPU.And that's where this developer made their odd choice. This particular CPU had plenty of general purpose registers, and a bunch of special purpose registers, like a set of registers for controlling PWM generators. The developer either couldn't find the correct way to access the general purpose registers or didn't care to try, but either way, the end result was that they used the PWM registers for everything:
|
by Remy Porter on (#63JRC)
Sam worked on an application which needed to parse files out of a directory. There was a ticket to change the search path for those files to search an additional directory. That didn't turn out to be terribly hard, but the existing code raised some serious eyebrows.
|
by Remy Porter on (#63HCN)
Robert H was trawling through the JavaScript front-end for his team's ASP.NET MVC application. The goal was to prepare for a complete rewrite of the front-end, because, well, it had problems and wasn't reliable or maintainable.As an example, Robert sends this:
|
by Lyle Seaman on (#63EDH)
Never let it be said that we at TDWTFdon't enjoy the taste of our own medicine. Andrew I. shares with us a little taste ofhis own crow, and then we share with you a little taste of Remy's. It's not quite a full meal, but you can call it anamuse bouche.But first, Sam B. serves up some sure fled pie."This Brexit business is getting out of hand. Lenovosays even the United Kingdom has left the UK."
|
by Remy Porter on (#63D0J)
Pearl was paying down some technical debt. She was trawling through their NodeJS application with a search for TODO and console.log. She was triaging the TODOs, and replacing the logs with a real logging framework.The application was old, had many complicated routes for requests to be handled, and buried deep in a file was this code, which was clearly testing code that was never meant to end up in production:
|
by Remy Porter on (#63BKN)
Usually, we don't pick on game code, as it's frequently bad because of the time constraints under which it's developed and because the concerns are more around "making a fun, performant game," and not "writing good reusable code".But there are some egregious exceptions, like what happened to Patrick. He was handed some C# game code, and told, "Good luck!"This particular block lived in a file called banana.cs. Does this game have anything to do with bananas? It does not! It has to do with zombies. No, it is not Plants vs. Zombies, though given the botanical flair in this code, perhaps the author was a fan?One module of the game uses integers as the ID values of enemies. One module uses strings. No one uses enums. So when you want to convert the IDs to the appropriate type, you need to call enemyIdNumToName, which I want to stress- is not the display name of the enemy.
|
by Remy Porter on (#63A4A)
"Phillip, are you familiar with SNMP? Do you know Python?" asked Phillip's new boss."No.""Would you like to be?"That's how Phillip got thrown into the deep end of a conversion project that was tasked with updating their infrastructure monitoring system. It was developed by a team a few years ago, and they all quit at the same time, which made it hard to maintain.It was a homegrown set of Python scripts which polled a Prometheus service, which itself was gathering metrics from a pile of Docker containers. These scripts gathered those events and turned them into SNMP alerts for a third party receiver.The upgrade promised to be simple: take the SNMPv2c code and update it to use SNMPv3, which supports encryption. Phillip started by pulling the existing code from their repository, only to find that while there was a repository and it had a pile of branches, nothing had ever been merged into main/master/trunk. So Phillip pinged one of the other developers: "Which is the correct version of the code?"He started playing with the PySNMP library while he waited. From reading the docs, Phillip thought that it should be a very simple change- essentially a find/replace to update one class name. After a few days of poking at the library, the previous developer gave him about three candidate branches which were probably what was actually deployed. Phillip found a Docker image that seemed to have the same code as one of those branches, and was probably the one deployed- no one knew for certain- and set to work.His first attempt didn't work at all, which wasn't surprising. There was no logging, the configuration was hard-coded in half a dozen places in the code and didn't always agree with the other places, and someplace along the way it needed an SNMP command, which nothing was sending. It was mess, but eventually, Phillip got it running.For a few minutes, anyway. Then it would crash. It took Phillip two months of research and experimentation to discover that the SnmpEngine object wasn't threadsafe. It wasn't his choice to use it across multiple threads- that was the architecture that the previous developers had used.That's when it dawned on Phillip: this program had never worked. Sure enough, the deployed version crashed all the time, too. So Phillip set about refactoring and debugging it, and after two more months, he had a thing that could read the metrics and report them to SNMP.Except the third-party receiver that expected to receive those messages didn't get them. Phillip could confirm he was sending it, but it wasn't arriving. Cue another month of scrambling and head-scratching, only for Phillip to discover that the network team had blocked the routes from the server he was running on and the third-party receiver."Oh, it was sending so much traffic, we assumed it was broken," was the best explanation he could get.So the service never worked in the first place. Even if it had worked, the network team had blocked it from working. No one talked to anyone else about what was going on. And, as the cherry on top of the sundae, the main customer for this data didn't believe in "on-call rotations"- they got ahold of the developers' cellphone numbers and called them directly whenever they had an issue.All that added up to Phillip leaving the company after a very long six months. It also neatly explained why the previous dev team had all quit en masse."Still," Phillip writes, "at least I got some Python experience out of it." [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!
|
by Alex Papadimoulis on (#638YZ)
|
by Lyle Seaman on (#63669)
Last week's article nearly exposed to the public the lowest-keytechreligious war that has been waging for decades. PEBKAC versus PEBCAK completely underwhelmsthe emacs vs vi war, the GUI vs CUI massacre, the tabs vsspaces schism, and even the -- + // alliance against the/* and (* comment markers. Scratch a PEBCAK partisan andall you'll find is a bit of blood and a response of "OW! Why did you do that?! There isn't any war!!" Even thepartisans deny it exists but it simmers. It's PEBKAC, Itell you. PEBKAC! Wait, I forgot. Which did I use inlast week's article?Plotzed publican Peter G. has tired of his local and decidedhe'd rather pop round todas Lokal for a schnitzel. Researchingreviews, he was surprised by an unexpected mountain PICNIC(Problem In Chair Not In Computer)."Dumont Travel seem to think the Anschluss is still in effect,or at least this is what you get when you ask for travelinfo for Austria (Österreich)."
|
by Remy Porter on (#634SG)
My favorite bar in Pittsburgh is a bit of a dive. Like any good dive, the bathroom is covered in the incoherent scrawl of thousands of drunks. It's a mix of jokes, political flamewars, and just absolute nonsense. My favorite part about it, though, is that it just makes me think about the long history of latrinalia. For as long as there have been humans, we've been scribbling on whatever surface was at hand, and a lot of those scribbles have been made while we answer nature's call.Programmers have their own form of latrinalia: code comments. They're frequently vulgar, they're sometimes comprehensible only to the person who wrote them, and we all like to pretend that they're more meaningful than they are.So let's take a look at a few mysterious scribbles on the bathroom walls of code.We start with this one, from Johann:
|
by Remy Porter on (#633E6)
Rachel is doing some Python/Django work on an application that, among other things, handles a pile of Internet addresses, a mix of IP addresses and domain names. Since each of those has a very different query path (domains could be filtered on the TLD or the name portion of the domain, for example), Rachel implemented some helper objects built on Django observables, the IPAddressObservable and the DomainObservable.This way, when someone wanted to search the database for an address, some code like this could run:
|
by Remy Porter on (#63243)
Circa 1999, Drake C was working on a video game for a large publisher. The game in question was a flight simulator with multiplayer dogfighting capabilities. Or at least, it was supposed to have multiplayer capabilities- in Drake's case, it just had a series of ugly crashes.The networking library came from the publisher, so Drake reached out to Karl, the developer of said library. They spent some time going back and forth over the phone and email, trying to troubleshoot it. Eventually, Karl tapped out. "I'm stumped," he admitted, "but I'll tell you what, we've got another team working on Weighty Cogs II, and they've already got multiplayer working. I'll get them to send you their code, so you can take a look. Should have it to you by this afternoon.""Oh," Drake said, "that'd be great. There's no rush, I've got plenty other tasks to work on, but yeah, if you can get that to me, that'd be super helpful."Drake moved on to those other tasks, and made a note to follow up with Karl. Half an hour later, Karl sent an email. CCed was the Weighty Cogs II team lead, the WC2 product manager, a developer from WC2, and a name Drake didn't recognize. The body was brief: "Please send Drake the network code."That itself kicked off another flurry of emails- another chain of names that Drake didn't recognize picked up the thread, forwarded the email around, kept Drake CCed on it, and just generally escalated through an obscure series of other owners, with the command: "Please put this together."Days passed. Drake kept hacking away at the many other tasks he had to work on. Every once in awhile, those tasks brought him into contact with Karl again, and when he did, he'd always ask, "Hey, is there any progress on getting me that code? Still no rush, but just trying to check the status."Karl would promise a follow up, and they'd continue.The email thread continued to tick away. It got passed from hand to hand, gradually wending its way up the digestive track of the publisher, until it finally started tickling the tonsils of some VPs. The tone of the email chain went from, "we need to do this," to "why hasn't this happened yet?"Outside of the email thread, there was a separate thread, involving those VPs, management, the entire Weighty Cogs II team, yet another development studio that was also doing a multiplayer game, and a few other odd names for good measure. This particular thread was a bit more panicked in tone, and lots of the information was getting lost. Suddenly, Drake hadn't simply accepted an offer of some network code from the WC2 team, he had demanded the entirety of the WC2 codebase. That team was from a different studio, so obviously they didn't want to just hand over all their code to a competitor. The publisher, however, didn't care what they wanted, since they owned all the rights. Somehow, the VPs had decided that this was on the critical path to hitting their release dates, and that if it didn't happen, Drake's project might be a complete failure. Which didn't endear Drake's team to the WC2 team at all- why should they bail out those failures?After a lot of screaming, several contentious conference calls, and a few C-suite meetings, this panic trickled back down the organization to Drake's boss, Mikey.Mikey stopped by Drake's cube. "Hey, Drake? Did you ask for the entirety of the Weighty Cogs II source code to be drop shipped on CD to you ASAP or we'd fail to ship?""What!? No!" Drake explained his request, and Mikey nodded."Okay, that makes sense. But you need to stop asking for it, because it's blown up to a thing."Mikey and Drake chuckled about the absurdity of the situation, and Drake stopped poking Karl about the software.The source code did finally arrive, at the start of the following week. It was shipped on CD, and the networking code was spaghettified into the game logic code, which both meant that it was difficult to trace, and also not reusable for Drake's task at all. But it did offer enough of an example that Drake could tell that his understanding of the networking library was correct. With that confidence, he was able to comb through his code until finally identifying the, in his words, "boneheaded mistake" in his code which caused the crash. [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!
|
by Remy Porter on (#630VZ)
As we frequently discuss here, many versions ago, Java added functional programming expressions, which can allow a developer to write very expressive, simple code. Of course, we don't cover any of those uses, because that's all fine.Kevin L used to work for a Fortune 500 company, and that company was full of developers who got very excited about those functional programming features in Java. Very excited. Too excited, if we're being honest.For example, if they wanted to check if an object was null, they might do this:
|
by Lyle Seaman on (#62Y4Z)
Today's amusements include a couple of twofers: one from a mouse,and two not-quite-canonical Error'ds that still manage to be pretty double you tee effy.First up, an eponymous anonymous shared what unlimited looks like."Thanks for the additional disk space," they squeaked. "That should cover me for a while." I suspect this is some kind of network drive, as I vaguely recall having seen something similar decades ago.
|
by Remy Porter on (#62WRB)
A common anti-pattern is the "expanded conditional". You know the drill:
|
by Ellis Morning on (#62VEA)
Alyssa worked in a shop building small runs of custom hardware. Recently, she tackled a project that involved an Arduino talking to an LCD screen. Since several programmers had just left their jobs, she was the last programmer standing and thus on her own for this assignment. One of the engineers who'd worked there before her had really liked a particular brand of programmable displays because they came with software that allowed non-programmers to design serial-driven user interfaces, and had its own onboard processor. That was what Alyssa wound up using for this project.Alyssa first tried to control the screens using the manufacturer's own serial library. She couldn't get any of the system commands to work over that serial library, but they did work if she used the manufacturer's test programs, running on the screen's onboard processor. Those would get uploaded via Serial, and sure enough, Alyssa could send commands over serial, just not using the vendor's library.This led her to try programming the screen directly ... which turned out to be a very bad decision.The manufacturer had come up with their own language. It was almost C, except there was only one data type: 16-bit integers. Want pointers? We're running on 16-bit hardware, so just use integers. Want strings? Use arrays of ints, two chars to the int! Want structs? No, of course not, who uses those? You can just use int arrays and manual byte offsets, right? Who needs type safety?If the language was bad, the documentation that struggled to rationalize its existence was worse. Sections had been copy/pasted wholesale without anyone remembering to go back and tweak them, leading to incorrect information everywhere one looked. References to other manuals contained no links or information on how to find them other than "use the site's search function." Drawing dimensions were flat-out wrong.In desperation, Alyssa visited the user forums for help, only to find scads of people like herself begging the manufacturer to let them use C on the screens. The manufacturer refused on the grounds that their language was more "beginner friendly" and that C wasn't "portable enough."After two weeks of this agony, Alyssa recalled that sending serial commands directly had worked before. She wrote some small utilities that completely routed around the manufacturer's software and finally got everything up and running. Upon congratulating her, Alyssa's boss also suggested selling her utilities to the manufacturer, which at this point could only be an improvement. [Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!
|
by Remy Porter on (#62T3J)
Here's one you've seen before. Somebody Fran works with heard that magic numbers were bad, and that you should use constants, so they did this:
|
by Remy Porter on (#62RVH)
For twenty years, Initech didn't have any sort of internal IT or anyone doing any sort of cohesive software purchasing or internal development strategy. Of course, as the company grew, they needed customized applications. With no official approach to doing this, the users did the best they could, using the developer tool installed on nearly every corporate Windows workstation: Microsoft Access.That's when Kris got hired, along with a pile of other developers. The team had one simple mission: convert these Access applications into "real" applications.Like pretty much every one of these projects, there were no requirements, beyond, "it should do the same thing as the existing application, but not be a fragile mess of overgrown code developed by people who didn't know what they were doing beyond just making it work". This meant that for a lot of the requirements analysis, Kris and the team needed to just trace through the code and try and figure out what it was doing.By the standards of these kinds of applications, the code was better than average, but that still didn't mean it was fun reading. Since there was no source control, old versions of the code just lived on in comments, and that lead to some of these sorts of head scratchers:
|
by Lyle Seaman on (#62P5B)
As always, dates are hard, memory management is hard, and localization is hard, but nothing, nothing is as hard as multiplication.Sushi fanBen A. found the freshest fish in western NY."After an earlier email thanking me for a non-existentrecent order," he confides, "Beyond Menu has helpfully clarified thatthey can predict the future."
|
by Remy Porter on (#62MW1)
Veteran developer and frequent contributor, Argle, once worked for a company which handled shipping. On April 3rd, 1988, a C function which used to work stopped working. What's so special about April 3rd of that year? Why, that's when the United States Post Office changed their rates.The post office changed their rates on a fairly regular cadence, of course. The previous change had been in 1985. Thus the developers had planned ahead, and decided that they wanted to make the rates easy to change. Now, this was mid-80s C code, so they weren't quite thinking in terms like "store it in a database", but instead took what felt like the path of least resistance: they created a lookup table. The function accepted the weight of a piece of postage, checked it against a lookup table, and returned the shipping price.Clearly, whoever had updated the table had made a mistake somewhere. The developer tasked with tracking down the bug printed out a code listing and pored over it. They couldn't spot the bug. They passed it off to another developer. And another. Each traced through the code, looking for some sort of obvious logical bug. They were all competent developers, this organization wasn't a WTF factory, so it ended up being quite a puzzle to each of them.Finally, the listing landed in Argle's hands.I'm making this code up, but the old version of the lookup table might have looked something like:
|
by Remy Porter on (#62KHA)
In the mid-00s, famous Web plugin Flash tried to make a pivot. It wasn't going to be for games or little animations anymore, it was going to be for Enterprise Applications, and they called it Flex.Flex was a pile of XML files and ActionScript which would be compiled together into a Flash-based UI that would work in every browser (with the Flash plugin). This was a terrible idea to begin with, and was basically killed pretty quickly by Apple releasing the iPhone without Flash, but for a brief moment, it was a product people used. It's was "donated" to Apache in 2012, as what I can only assume was a White Elephant.But in 2008, the SDK went open source. And it's from this era that today's sample from Steven comes.Steven was trawling through the SDK trying to understand why performance was bad. While this method wasn't the thing killing performance, but it was called everywhere, and left Steven scratching his head.
|
by Remy Porter on (#62J9B)
Bruce W's employer was best described as The Mega Bureaucracy. It's the kind of place where it takes twenty weeks to provision web servers, because of the number of forms, checkpoints, and management sign-offs involved. The Mega Bureaucracy did all of this because it kept their environment "stable", and equally important, "secure".Speaking of security, the Mega Bureaucracy needed to expand its offices, and went out and constructed two new fourteen story office buildings which would serve as their headquarters. These offices needed to be validated for security, and Bruce was invited to be on the team that would perform the assessment. The first area they visited was the mailroom which served both buildings.Of course, there was great concern over mailroom security. You didn't want things being added to or removed from the mailstream without going through the right process. This meant that the mailroom needed physical access controls: only authorized personnel should be allowed into the mailroom. Everything entering and leaving the mailroom had to pass through a control point.Bruce and the rest of the assessors did a walkthrough of the mailroom space, and verified each of those steps. As one might expect from the Mega Bureaucracy, a lot of overhead and control had been added to the mail-handling process, but the result was that the mail wouldn't be easily tampered with by unauthorized users. Satisfied, the tour group left the secure side of the mailroom, and clambered into the elevator to examine the next floor of the building.Bruce noticed that there were some stragglers, so he hit the "door open" button in the elevator. Except this was an elevator with doors on either side, and Bruce had actually hit the door open button for the opposing doors. They dutifully slid open, revealing the secure side of the mailroom. Anyone with access to this elevator (which was anyone in the building) could access the mailroom by simply pushing the "door open" button, circumventing the many, many security checks that the Mega Bureaucracy had put in place.This was, as one might imagine, a problem. Bruce and his team raised the problem, which triggered a barrage of finger-pointing, name-calling, and extreme blamestorming as every entity involved in designing the building wanted to throw the other entity under the bus. The company that constructed the building claimed they built it to spec. Mega Bureaucracy claimed that they had not. The team that approved the design of the building claimed that their spec included these security checks, the elevator installer was emphatic that no such thing had happened. The refrain from everyone involved in construction was: "There is no problem, we built the best buildings, your expectations are wrong."This is where the Mega Bureaucracy fell apart. Their entire bureaucratic system of command and control was entirely built around preventing these kinds of situations from arising. The number of signoffs and checkpoints was to prevent failures. As it turned out, there was no bureaucratic system to recover from failures. Instead, everyone just blamed everyone else for not having checked the right boxes, and the building started operating with a mailroom that anyone off the street could just wander into.With no bureaucratic solution, Bruce took matters into his own hands. He called the building manager. The building manager cut him off with the refrain: "We built the best building.""That's fine," Bruce said, "but why don't you meet me in the elevator in ten minutes, so I can show you what's happening."Ten minutes later, Bruce met the building manager in the elevator. Five minutes after that, the building manager sent out an email announcing that they'd be adding a card reader to the elevator to control access to the mailroom. All in all, from the time they identified the problem to the time when it was finally resolved was brief, by the standards of The Mega Bureaucracy: three months. [Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!
|
by Remy Porter on (#62H1K)
Mindy recently had an interview. It started off quite well. The company seemed to be well run, the first few folks Mindy talked too seemed nice enough. And then she sat down with their lead developer, Davin."What's your experience with SQL Server stored procedures?" Davin asked."Oh, well, you know, I'll sometimes use them as prepared queries, if performance tuning calls for it, but I always avoid implementing business logic in a stored procedure beca-""No business logic in the stored procedures? I take that as an insult," Davin said. "SQL Server has all the power you need, and trying to scale out the web layer will cost money!""Sure," Mindy said, "but it's much harder to scale out the database layer, and diffic-""For instance," Davin said, "I've written a hyperoptimized stored procedure to handle StartsWith queries.""You… wrote a starts with method?" Mindy asked. "I mean, if it were me, I'd probably do a column = 'prefix%, or maybe CharIndex…""No! Building a search tree is much faster. My code builds a tree out of the string to compare the incoming string. Then, when searching, I don't need to look at every character.""But… don't you have to look at every character to build the tree?"Davin blinked, and then said, "It's much faster to use a tree."The interview ended not much later. A few days after that, the recruiter called Mindy to let her know that the company had decided not to move forward with her. In the end, she didn't really mind that outcome. [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!
|
by Lyle Seaman on (#62E8T)
There's no real theme to be gleaned from this week's submissions, just the usual sort of things and a tiny serving of irony courtesy of Google.Undercover QA engineer Randy O. somehow provoked British Gas to refuse to quote him a meaningful fee."I uploaded my meter readings to the BritishGas website, and they updated my estimated bill," he explained. "When they want me to pay it I may just say NaH." And that's no lye.
|
by Remy Porter on (#62CZW)
While browsing one day, Emma clicked a link on a site and nothing happened. That was annoying, but Emma wasn't about to give up. She tried to get the URL out of the link, only to discover that there wasn't a URL. Or a link. A quick trip to the DOM inspector highlighted what was going on:
|
by Remy Porter on (#62BQX)
NoSQL databases frequently are designed to shard or partition across many nodes. That, of course, makes enforcing unique IDs different than you might do in a SQL database. You can't efficiently have an autoincrement sequence, and instead have to have something like a UUID.But if you've designed your NoSQL database badly, or your input data isn't well sanitized, you might find yourself in a situation where you can't guarantee uniqueness without validating every row. That's a bad place to be, but it's probably how the code Remco found started its life.The purpose of this Java code is to query all the customer IDs from a database and ensure that they're fully unique.
|
by Remy Porter on (#62AGJ)
David was poking around in some code for a visualization library his team uses. It's a pretty potent tool, with good code quality. While skimming the code, though, David found this mismatched comment and code:
|
by Remy Porter on (#62939)
Michael was assigned a short, investigatory ticket. You see, their PHP application allowed file uploads. They had a rule: the files should never be larger than 20MB. But someone had uploaded files which were larger. Not much larger, but larger. Michael was tasked with figuring out what was wrong.Given that the error was less than half a megabyte, Michael had a pretty good guess about why this was.
|
by Lyle Seaman on (#626E1)
England and the United States, according tothe old witticism, are two countries separated by a common language. Thefirst sample deposited in our inbox by Philip B. this week probably demonstrates the aphorism. "I'm all in favor of high-tech solutionsbut what happens if I only want (ahem) a Number One?" he asked. I read, and read again, and couldn't find theslightest thing funny about it. Then I realized that it must be a Brit thing.
|
by Remy Porter on (#62534)
The startup life is difficult, at the best of times. It's extra hard when the startup's entire bundle of C-level executives are seniors in college. For the company Aniket Bhattacharyea worked for, they had a product, they had a plan, and they had funding from a Venture Capitalist. More than funding, the VC had their own irons in the fire, and they'd toss subcontracting work to Aniket's startup. It kept the lights on, but it also ate up their capacity to progress the startup's product.One day, the VC had a new product to launch: a children's clothing store. The minimum viable product, in this case, was just a Magento demo with a Vue Storefront front-end. Strict tutorial-mode stuff, which the VC planned to present to stakeholders as an example of what their product could be.Everything was going fine until five minutes before the demo. The VC discovered a show-stopping problem: "The storefront is showing obscene images!"The "obscene" pictures were just photographs of female models, typical for a clothing storefront. But since this was a children's store, the VC was in a panic. "I can't demo this to other investors!"Setting aside the problems of why the VC hadn't noticed this more than five minutes before, Aniket was given his mission: take a pile of replacement images and upload them to the server.Well, with the configuration the server had, there was no way to upload images through the UI. Aniket could SSH in, but that presented a new problem: he didn't have write access to the directory where the files lived.While Aniket tried to make a plan of how to fix this, his phone blew up with texts from both the VC and from the CEO of Aniket's startup. "What's the status?" "What's the ETA?" "You need to go faster."Aniket couldn't overwrite the images, but he did have access to some commands via sudo, specifically managing Nginx. And that gave Aniket an idea.All the images served by the storefront lived under the url /images. Aniket wrote an Nginx rule to redirect /images to port 8000, dropped the new images in a directory that he did have write access to, and then ran python -m http.server 8000 to launch a webserver hosting the files in that directory on port 8000.The VC got to start their demo on time. Aniket closed his laptop and texted his CEO. "I've done the job, but my laptop is now broken. I'm going to take it in for repair." Aniket then went out for a much needed walk and took the rest of the afternoon off. [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!
|
by Remy Porter on (#623S5)
"When inventory drops below the re-order level, we automatically order more," was how the product owner described the requirement to the junior developer. The junior toddled off to work, made their changes. They were not, however, given sufficient supervision, any additional guidance, or any code-reviews.Dan found this in production:
|
by Remy Porter on (#622F5)
Microsoft Access represents an "attractive nuisance". It's a powerful database and application development platform designed to enable end users to manage their own data. Empowering users is, in principle, good. But the negative side effect is that you get people who aren't application developers developing applications, which inevitably become business critical.A small company developed an Access Database thirty years ago. It grew, it mutated, it got ported from each Access version to the next. Its tendrils extended outwards, taking over more and more of the business's processes. The ability to maintain and modify the database decayed, updates and bugfixes got slower to make, the whole system got slower. But it limped along roughly at the speed the business required… and then Larry, the user who developed, retired.And that's where Henrietta comes in. She was hired on contract to take this ancient, crufty, Access database and reimplement it in C#, with a WPF front end (because "web application" sounded too scary a shift), with a SQL Server backend. The project was already in-flight, under the sober guidance of internal developers who had analyzed the Access database in detail.There was already a source control server set up- an SVN server. Henrietta found that odd, but odder still was the change history: 100,000 commits from fewer than 20 developers, in only six years. Now, that's not ridiculous- but it's a steady cadence of two commits per developer per day, including weekends and holidays.There was, fortunately, a lot of documentation. None of it was about the code, but instead about the organization. Who works for who, when a given management position was created, how long someone had been in that position. Nothing about the software internals. Definitely nothing about the custom UI framework someone had bolted on top of WPF.When Henrietta noticed she couldn't find documentation about coding standards, or code review processes, she went to one of the other developers and asked: "What's our coding standard? And how do we handle code reviews?""Our whats? I don't know what those are."Well, Henrietta finished up her first ticket, had her commit, and then did what all the other developers did: committed it right into the trunk of the repository.Now, that was her first commit, and it was a training commit: she just needed to add some validation to the UI to make sure it didn't allow empty form fields. With that under her belt, her boss assigned her a new, more complex task. It needed her to make changes in the database, add new workflows to the application, a few screens, and so on."So," she asked, "is there a spec for this somewhere?""Oh," her boss said, "we don't write specs before we develop. Develop the feature and then write specs to describe its behavior."Well, Henrietta didn't like to work that way, so she started by drawing mockups in a diagramming tool. This, as it turned out, was completely new to the organization. No one had ever done a screen mock up before. The handful of diagrams that did exist all were drawn with the same tool: Microsoft Paint.Once Henrietta had decided what her feature was going to look like, she made a feature branch to start her work- and discovered that the way the application was architected, you couldn't conveniently develop in a local branch. In fact, you couldn't even get it to easily point at a development database. Everything had to go through trunk and get pushed to a dev server for testing- one dev server which all the developers had to share.When Henrietta's code didn't work, she found out why: there was a "convenience library" developed by her boss that contained critical functionality for the application. If you didn't call certain methods in that library, the application wouldn't work. These methods were undocumented, and also, no one knew where the code lived. They only used the binary, compiled version of the library.Once Henrietta had reshaped her code around the arcane bondage that the library demanded of her, she had reached the point where she didn't understand her own code anymore. Before she can get into the work of testing the code, a new issue rises to the top of the priority list and she's told to stop what she's doing and tackle that.This was meant to integrate into a 3rd party SOAP-based web service. It transports sensitive data… over HTTP. There's no encryption at all. The WSDL file contains overlapping definitions of two different versions of the API, and the contradictions mean it's possible and easy to send malformed requests with unpredictable behavior. And when it does catch an error, it simply responds with "Error".At this point, months had passed. So it was time for the organization to change their tooling. Everyone was commanded to update to the newest version of .NET Core, a new version of the IDE, and now a new code review tool. Crucible was rolled out with no instructions or guidance, and developers were expected to just start using it.This delayed Henrietta's work on the 3rd party interface, so she went back to the complex feature with database changes. She discovered there are no foreign keys. Also, because there weren't any foreign keys, the data can't have foreign keys added, because the columns that should enforce referential integrity don't match up correctly.Meanwhile, the Project Owner, frustrated by the slow development progress, started writing code themselves. They used the wrong set of project files, pushed it directly to a customer, and caused multiple crashes and downtime for that customer.Back to the database, Henrietta discovered that there's really no abstraction around it, implementation details of the database have to be reimplemented into the UI. She built a UI control that encapsulated at least some of that functionality, and added it to the global UI library. Her boss noticed that change, and told her, "no, that's specific to your module, put it in a local library." Her boss's boss noticed that change, and said, "that UI control is very useful, put it in the global library."Neither boss could agree on the correct location for it, so as a compromise, they created a new "global" library for "accessory controls".Frustrated by all of this, Henrietta decided that she should try and get a local development environment set up. She ended up spending a few days on this, only to discover that certain stored procedures call out to other databases via hard-coded connection strings, and if she tried to run a local copy she'd simply start mangling data in other, production databases. Her boss noticed her spending time on this, and complained that she was wasting her time.When Henrietta finally finished her big feature, she deployed it to the test environment. It blew up, but for reasons she could easily understand, and it only took a few days to fix it. The customer tested the feature, and it wasn't what they thought it was going to be. Once they understood the requirements, which weren't their original requirements, they were happy with the feature, but wished they'd gotten the feature they asked for. With this sign off, the Henrietta pushed the change to production, manually (because why would you automate deployments?). The customer's application immediately crashed because their database was incompatible with the current version of the code. There was, of course, no rollback procedure, so Henrietta was expected to spend a weekend combing through the customer's database to figure out which field contained a value that crashed the application.After that, frustrated, Henrietta went to her boss. "Why are we doing things this way? We're spinning our wheels and making no progress because we have no process, no organization, and everything we do is fragile and we're not doing anything to fix the fundamental problems.""That's the way we do it," her boss said. "Stop asking questions about everything, don't question anything, we're not going to change that. Just do your work or find a new job."Henrietta took that advice to heart, and found a new job. All in all, she spent 8 months fighting her way upstream against a river of crap. It wasn't worth it. [Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!
|
by Remy Porter on (#6217H)
In November of 2020, the last IE release happened, and on June 15th of this year, the desktop app officially lost support on Windows 10. But IE never truly dies.Eleanor inherited a web application for a news service. And, you won't be shocked that it's still doing user-agent sniffing to identify the browser. That's just plain bad, but by the standards of user-agent sniffing, it's not terrible code.
|
by Lyle Seaman on (#61YBZ)
So much cringe here today. Obviously, the first submission belowjust reeks of professional sycophantry on so many levels. I can'tdecide which is more offensive, the barefoot butcher or the grotesqueattempt to humanize a vogon. To take the edge off, I'll start youout with a very old shaggy dog punchline. The actual setup for thisgroaner is pretty horrible, though someone on the internet has dutifullycompiled the definitive collection of all known variants. Sparingyou that misery, I'll cut straight to the chase: Rudolf the Redknows rain, dear. Now you can decide which gag is more worthy: that, or this.My English vocabulary cannot convey the complexity of my feelings aboutBeatrix W. who shared a monstrosity, reporting innocently"I was just looking for a book about AppleScript by a Japanese author." Is there aJapanese word for "thank you for this gift but never do it again?"
|
by Remy Porter on (#61X09)
CSS classes give us the ability to reuse styles in a meaningful way, by defining, well, classes of styling. A common anti-pattern is to misuse classes and define things like "redTextUnderlined" as a CSS class. Best practice is that a CSS class should define the role, not the appearance. So that class might be better named "validationError", for example. A class will frequently bundle together a bunch of stylesheet properties into a single, meaningful name. That's the ideal approach, anyway.Now, Olivia's predecessor had an… interesting philosophy of how to use CSS classes.
|