|
by Remy Porter on (#6G58P)
Power outages are never good, and they're even worse when your facility needs to run 24/7. Now, Jaroslaw's organization didn't do a great job setting up for round-the-clock, always-on operations. It was the kind of thing where the organization grew, annexed the neighboring building, and kept growing. The result was hundreds of workstations, two separate power lines, two server rooms, three different Internet uplinks, and huge piles of switches responsible for making this network work.Which added the problem that after a power outage, nothing came back on exactly right, either. It always took some time to find the one switch that opted not to reboot.Now, many years earlier, someone had the bright idea of installing a generator. The hookup offered no easy way to switch over to generator power, and thus required an electrician with keys to the elecrtical boxes to actually make the change. While the servers had small UPSes, enough of the environment went down during a power outage that, by the time they had the generator on and everything powered back up properly, the outage was usually over.And so it went for years, until someone higher up looked at the problem and freed up the budget to fix things. The generator was replaced, and there was a plan to change the wiring so that it was faster to switch over- but it turned out that would have tripled the budget and shut the facility down for days while electricians redid the whole electrical system. Instead, the budget was used to upgrade from small, consumer-grade UPSes to a big hocking, 10kW unit.It was the size of a large refrigerator, and had enough power to keep all the critical elements of the facility powered on for twenty hours- time enough to switch over to the generator, if needed.And then, miracle of miracles, they tested their switchover plan. They cut main power, saw the UPS come on, ensured work could continue, then had the electricians switch on the generator, and then reversed the whole process. It went off without a hitch.And then a week later, the UPS screamed about an overload. It lasted for about 40 seconds, then cleared up. Considering that the UPS had way more capacity than they needed, that seemed like a serious problem. Two hours later, it happened again. And again. And again. Jaroslaw went through everything in the server room, trying to find the badly behaved device. At one point, he found an unplugged electric kettle sitting not far from the server room, and went on a hunt to see if anyone had been making tea in the server room, thinking that was the culprit. No one had.Over three days, after checking all the equipment, Jaroslaw went to the building wiring diagram and started checking every outlet. He found one, hidden in the back of the server room, ostensibly unused, that had an extension cord plugged in. The cord was neatly tucked into the cable chase, as if it was part of the plan. Jaroslaw tracked the cable, and followed it around the room until he found a hidden refrigerator. Some of the 24/7 staff wanted easy access to snacks and drinks, and didn't want to constantly badge in and out of the server room to get them. While there were plenty of non-UPS protected outlets they could have used, someone had decided this was a better option.And sure enough, while Jaroslaw was looking at the fridge, he heard the compressor kick on, and the UPS scream about an overload at the same time.The immediate fix was easy: remove the fridge and extension cord, and have a serious discussion about proper server room safety. The longer term fix was spending the last bits of the budget to add keyed switches to all of the outlets in the server room, ensuring no one could plug things in without going through the proper channels. [Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.
|
The Daily WTF
| Link | http://thedailywtf.com/ |
| Feed | http://syndication.thedailywtf.com/TheDailyWtf |
| Updated | 2025-12-13 09:47 |
|
by Lyle Seaman on (#6G474)
Hungry Adam starts off your RSS feed with what might honestly be making the best of a bad situation."I guess my pizza will be here next time I write a date bug?"
|
|
by Remy Porter on (#6G1EC)
Let's say you were browsing through some code, and saw a function signature like this:
|
|
by Remy Porter on (#6G0E7)
Today is Halloween, a day filled with chills, horrors, and Jamie Lee Curtis. An interesting aspect of horror movies is how often the roots of the horror lurk in the past. Michael Meyers had been in an asylum for decades before his infamous Halloween rampage. Midsommar represents a centuries old tradition. Barbarian is rooted in sins committed a generation prior. Freddy Krueger was the manifestation of the sins of our protagonists' parents. Hell, even Dracula is a menace that had been lurking for centuries before our story begins.In honor of that, we're going to look at some code from Davide. Like so much classic horror, the seeds of this sin were planted many, many years before Davide arrived.In 1991, Microsoft released their first version of Visual Basic. The language evolved until 1998, with the release of VB6. Mainstream support ended in 2005, extended support ended in 2008, but like true horror, VB6 has not truly died. The development tools continue to run on all 32-bit versions of Windows.Back in those olden days, Davide's predecessors decided to implement an Enterprise Resource Planning system in VB6. It grew, and evolved, and became something that couldn't be controlled anymore- it was 2.5M lines of code. It entangled itself into the company, taking over every core business function, and rapidly becoming indispensible.We can compare it to so many monsters of horror- the shapeshifting Thing, gradually replacing parts of the company with itself. The fungus from The Last of Us, taking over the brain of the company. We can compare it to The Blob, which may also be the most accurate description of the coding practices used in building it.Here's some code that evaluates a formula entered by the users:
|
|
by Remy Porter on (#6FZD4)
Aaron was doing some work with a high-performance-computing platform. The kind of thing that handles complex numerical simulations divided across farms of CPUs, GPUs, FPGAs, and basically anything else that computes.The system comes with a web GUI, and the code for the web GUI is... well... let's just look at the comment on a method.
|
|
by Lyle Seaman on (#6FXEX)
"My FB got HACKED" wrote an anonymous contributor. "Verification codes box sooo not funny " Not just one facepalm, but four.
|
|
by Remy Porter on (#6FWHE)
Once upon a time, someone wanted to store date ranges in a database. And so, they started down the obvious path of having two columns, one to hold the starting date of the range, and one to hold the ending date. But even going down that route, they tripped and fell, because they ended up with two database fields name Startdate and StartdateStart. Startdate was the end of the period.You might be thinking, "Well, at least they used the database datetime types," but on that front, you'd be wrong. They used text, and in some cases, instead of Startdate holding a date, it held a string in the format 22-08-2022 to 27-08-2023.Someone had to write code to parse that data, and that someone did the job and then left. Which meant Niels H had to support the resulting C#.
|
|
by Remy Porter on (#6FVFE)
Mark recently inherited a Java codebase that... well, it's going to need some support. He thought things were bad when he encountered this:
|
|
by Remy Porter on (#6FTG9)
Henrik H was hired by a customer to fix some bugs in their application. The main one was that their C# web app didn't properly track the user's culture settings. Henrik spoke with their internal developer, who originally wrote the application, and was told: "Sometimes the culture name and LCID is out of sync. I don't understand why?"Well, from that description, Henrik didn't understand either. Why was there a separate name and what the heck was LCID? Why were two variables getting synced? The only answer would be in the code, so Henrik dug in.
|
|
by Remy Porter on (#6FSZZ)
The rule of spelling in programming is that it doesn't matter if you spell it correctly, only if you spell it consistently. Which is fine if you're working alone, but we rarely work alone. And unless you're entire team shares the same misspelling habits, you're in for trouble when one person insists on "calander" while everyone else uses "calender".Fortunately, Jonathon's co-worker had a solution to this problem.
|
|
by Lyle Seaman on (#6FQNR)
This week, Harry Altman teaches us how to make sure thatautoautomobiles don't crash into your house. It's notimmediately obvious, and the answer to the puzzleborders on philosophical.But first, an anonymous reader wrote"I found this in a practice exam for an Azure Certification, !(Azure Service Bus) story."I believe him.
|
|
by Remy Porter on (#6FPQR)
The power of SQL is that you describe to the database what you want, and the database figures out how to execute that query as efficiently as possible. This means that, at least in theory, you optimize your database access not by changing the query, but by tuning the database to run that query efficiently.In practice, every database has quirks, and frequently you do tune the query a bit, to trick the optimizer into running it efficiently. And sometimes, you have to modify the query because people are dumb.Jakard was tracking down a performance issue in the database. There was one query that was taking over 30 minutes to produce less than 30 records. That seemed bad, so Jakard took a look at the query.
|
|
by Remy Porter on (#6FNXV)
Melissa was trying to figure out why an old application wasn't writing out a data file when commanded to do so. It was an implemented feature, it should work, it had worked at one point- but it wasn't working now.She traced through the C code and found this:
|
|
by Remy Porter on (#6FMR7)
Mr. TA inherited some C# code that communicates with a humidity and a temperature sensor. Each sensor logs a series of datapoints as they run, and can provide them as an array of data points.This leads to this code:
|
|
by Remy Porter on (#6FKQS)
Laurie has been supporting an internal application for a few years. The code is a mess, and while she wasn't at the company for the early stages of development, tales are told about it- it was chaotic, it was badly estimated, it was wildly over budget, the latter phases were a crunch where ten developers were shoved onto the project at the last second.Today, it works- mostly. But it provides plenty of support tickets for Laurie, and demonstrates some WTFs.One feature is that many forms have a "RESET" button. Push the button, clear out all the values on the form. Here's how that code looks:
|
|
by Lyle Seaman on (#6FHMS)
Winter is coming to New Mexico this year with a vengeance. It should be fine if you just stay out of the wind.First, to get this out of the way,never let it be said that we at TDWTF won't take our own lumps.The Beast in Black has a beef with our grammar, and technically he is correct."So Meta, Especially This Atrocity..."
|
|
by Remy Porter on (#6FGQS)
In the cinematic classic They Live, the protagonist is a drifter named "Nada"- nothing. Zizek derives much meaning from this, which is an entertaining rant if nothing else.But Nada appears in other places, like this code found by JMM.
|
|
by Remy Porter on (#6FFN6)
Dom works on a codebase which has fallen victim to Greenspun's Tenth Rule. Yes, they've implemented a user customization system that is an "ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp."Said Lisp implementation started its life as a Java backend, but over the years got ported into Flash apps, iOS, and most recently the JavaScript front end.While reviewing some of the tests on the JavaScript parser, Dom found some questionable understanding of JavaScript.
|
|
by Remy Porter on (#6FESK)
One of the secret powers of a relational database system, is that the query describing the data you want and the execution path for fetching it have no direct connection. The database is free to find optimizations and alternate paths for fetching the data. Coupled with database configurations like indexes and partitions, you can frequently take huge quantities of data and run arbitrary queries against it without having to think too hard about performance when writing the query (while spending a lot of time thinking about performance as you manage indexes and statistics gathering).That doesn't mean that we don't see some... unique choices in terms of how we organize our data "for performance". Chris needed to add a field to one of their data models. Said data model was generated from object oriented mapping, so it seemed like it should be easy to do. Just add a field to the object oriented model, generate a migration script, and then start the rollout process.It was not, in fact, easy. At first it was because whatever they had done in their underlying configuration meant that the ORM tool they were using couldn't successfully generate migration scripts. Fine, Chris could generate it by hand- it was one field after all. But applying that change in a test database showed that just adding the field wasn't sufficient- a bunch of materialized views needed to be modified to also fetch the field. Upon opening the code for the views, Chris also saw that simply changing the views wasn't going to be sufficient, because they didn't work the way anyone expected.Each view queried many hundreds of tables, all with the same schema. They were all named in the pattern MyDataset10OCT2023. Each one had a foreign key back to the previous day's table- MyDataset10OCT2023 linked back to MyDataset09OCT2023, which went back to MyDataset08OCT2023, and so on. The views joined all of those tables together to aggregate the data across the entire history, essentially summarizing a daily snapshot of all the ways the data changed.All of this was managed by a set of PL/SQL stored procedures, some of which generated the daily table, some of which regenerated the queries for the materialized views. All of this meant that Chris either had to add the field to every single daily table, or had to touch PL/SQL code that munged strings together to generate SQL queries that replaced materialized views.Given the options, changing every single table seemed easier and at least something that could be automated and tested. But Chris has no idea why there's essentially a linked list of database tables with daily snapshots, and asking the people who had been on the team for awhile didn't yield better answers than, "I think they did that for performance." [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!
|
|
by Remy Porter on (#6FDWH)
Several months ago, Rebecca's predecessor wrote some Perl code to traverse a JSON-esque data-structure. It was an hash map that could contain values, arrays, or more hashes.Said predecessor wrote the code, had it reviewed, and tested it. It rolled out in production, and for three months, everything was fine. Three months was also long enough for predecessor to take a new job elsewhere, which left Rebecca as the sole support when it broke.
|
|
by Lyle Seaman on (#6FBS8)
No fail merges today, no fexts or flubstitutes. Just flubs, subbed by a pantheon of old hands. I think everyone represented has been active here for at least five years, save perhaps our first, anonymous submission!An anonymous Aussie shared a snippet of source from the ozpo website. Notice that even their "suggested example" doesn't fit."Australia Post's most public of many rule mismatches in their n-number of systems chained together.The description text field on the printed label? Sure, there's space for over 900 characters."
|
|
by Remy Porter on (#6FAS3)
There is an entire category of WTF rooted in not understanding what HTTP status codes mean. As a quick refresher, the basic pattern is:
|
|
by Remy Porter on (#6F9QJ)
Many years ago, Valts and his spouse both worked for the same company. The company had an ERP system that started its life as a product back when ERP systems were novel and new. It was written in Delphi, and it was huge- so huge that the company needed to hack the Delphi linker to handle its size.Well, their company got swallowed up by Initech, and after the buyout, things changed. Valts left, and a few years later so did his spouse. But they kept in touch with their colleagues, so it was over dinner that former co-worker Viktorija related the recent disaster she had stumbled across.Viktorija's day started when she needed to modify one of the "Business Objects". This product started its life well before ORMs were a common tool, and someone had taken to inventing it in house, wrapping around Delphi's TDataSet object and plenty of hard-coded SQL strings. What she needed to modify was just a minor validation rule, which she quickly changed and tested, and was quite happy with.While making the change, she also spotted a hard-coded SQL string that was just... badly formatted. Since it made the query harder to read, and since she was right there, Viktorija added some spaces and breaks and generally made the formatting readable. She committed her changes and went on to the next task for the day.The CI jobs failed on her commit. But they failed in a completely unrelated module, which nothing she had changed should impact. Nothing about a changed validation rule even applied to that module, and the errors were about database access- nothing in Viktorija's change should impact database access...... well, aside from modifying a query.Viktorija revisited her changes, and noticed that there was a "getter" function to retrieve the value of the query string. She had assumed that was just for debugging purposes, but when she CTRL+Fed through the broken module, she saw that it was fetching that string. And then it was mangling that string.At some point, someone said, "Code reuse is always good, and since SQL queries are code, I'll reuse it!" So they fetched the query string from the Business Object Viktorija had changed, and then did a series of operations like "delete the substring from character 160-173" and "insert this substring at position 57."By altering the whitespace and formatting, Viktorija had broken that code. It was easy enough to make the tests pass- all Viktorija had to do was revert that part of the change. Unpicking the string mangling and trying to make the system not a disaster was a much larger challenge.Upon learning of this story, Valts and his partner were quite happy to have left- and felt that Viktorija should go home with an extra bottle of wine after dinner. [Advertisement] ProGet's got you covered with security and access controls on your NuGet feeds. Learn more.
|
|
by Remy Porter on (#6F8R1)
Gracie had a friend who was interested in becoming a teacher. To get admitted into a teaching program at the local university, the friend needed to take an admissions test, to prove they were teaching material.Said friend tried to retrieve their test results, and the page glitched out. Gracie, who was handy, offered to see if she could identify the problem- likely an ad-blocker extension or something was breaking a script. A few minutes in the browser debugging tools, however, showed that the script came pre-broken.
|
|
by Remy Porter on (#6F7V4)
Ensuring you code is readable is arguably one of the most important things you can do after ensuring it is correct. The real question is: readable to whom? Because apparently, some people have odd ideas about readability. Like Evan's co-worker.
|
|
by Lyle Seaman on (#6F5S0)
I read your minds today, and what I saw there said you're all desperate for more Error'd. Lucky you, here's a twofer from LinkedIn!Prospective employeeProgenitus opened an email and reflected "Yes, LinkedIn I am asking that myself. But I hoped you would help me find out about that."
|
|
by Remy Porter on (#6F4PJ)
Bleu supports a Pimcore-based PHP site. Pimcore is a rather sprawling enterprise system for PHP. Like many Model-View-Controller type frameworks, maps HTTP requests to actions on controllers. Bleu's team has several "default" actions configured on their controllers. Let's take a look at a few of them.
|
|
by Remy Porter on (#6F3QM)
Matt's team had a party after their last release. It was a huge push, with tons of new features, that came at the end of many months of work. On the Monday after the party, they came back into work for unsurprising bad news: nothing is perfect, so there were several issues and defects that needed to be patched, quickly.Since QA is the team responsible for signing off and approving any work, QA is the team that also owns the defect tickets. Matt and his team can't do any work without a ticket, which meant they spent almost an entire day knowing there were bugs to fix, but without any idea of what bugs to fix.The next day, QA finally finished triaging the issues. There were a slew of low priority tickets, none of which were bugs, but enhancement requests- this screen is confusing, this path through the application requires too many button presses, no one can find this option. There was, however, only one bug ticket."Hunh," Matt thought, "that doesn't sound so bad."Upon opening the ticket, Matt discovered that it was indeed bad. There were almost a dozen serious bugs, but for whatever reason, QA had bundled them into a single ticket. This made everybody's life much harder. Every change in the code had to have an associated ticket, every bug ticket had to have an attached test plan, every ticket has to have a single owner and assignee (but Matt's entire team would be splitting this work). Everything about getting this fixed was harder because QA had created a bottleneck by tying together unrelated bugs into a single ticket.So Matt went over to Bruce, the QA manager who'd created the ticket. "Could you please split this ticket?""No, I can't.""Yes, you can. Just abandon this one and make new ones."Bruce shook his head. "You don't understand. These are post release bugs. Which means we released software with bugs in it. Which means the QA process failed. When the management dashboard shows a dozen high priority bugs post-release, management thinks that someone wasn't doing their job properly. That looks bad. So, we make one ticket, roll all the issues under that one, and it looks much better on the dashboard."Matt was offended that anyone would try to game the system like that. QA was making everybody's job harder and trying to conceal issues from management. Well, the joke was on QA- Matt went straight up the tree to the management team.He sent an email, laying out what was happening, and most important, why it was happening. QA was trying to hide the failures in the QA process. Later that day, one of the directors set up a meeting with Matt to discuss the email."So, I understand you have some concerns," the VP said, "and I just wanted to show you how we view that." The VP pulled up the management dashboard, and flipped back to an old release, from a few years ago. Many of the metrics showed red stoplights. "So, here's a release that went badly. Too many tickets for bugs." They flipped to the most recent release. Here, all the lights were green. "And this is a release that went well.""Right," Matt said, "but this release only looks like it went well because they only opened one ticket for many bugs!"The VP nodded without listening. "Right, but this dashboard tracks open tickets. We like releases with only one open ticket. The lights are green, see?""But there are more bugs than there are tickets. They're hiding the fact that there are more bugs!""But this dashboard doesn't track bugs, it tracks tickets."There are few things more immovable than a manager with pretty green lights on a dashboard. Goodhart's Law struck again. Matt admitted defeat and fixed the ticket the hard way. [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!
|
|
by Remy Porter on (#6F2RQ)
Inilock started making locks back in the 1880s, and has always had a conservative approach to changing things about how locks work. But the world has moved on, and the pin-and-tumbler has given way to RFID card readers and electromagnets.Since Inilock didn't have the internal expertise to build industrial locking systems for commercial customers, they did what any company would do: they hired highly paid consultants. The project started in 2018. These consultants went out and build a lock firmware platform, a server, and a homegrown TCP protocol to handle configuration and setup, handed it in late and over budget, cashed their checks, and vanished, by 2022.The system was not too bad. It was extremely bad. The server used for configuring locks would hang on the regular. That was bad enough, but even worse, the locks would also stop responding. As it turns out, "have you tried turning it on and off again" is not something your customers want to hear when they're locked out of the building. The product was so bad, and had consumed so many resources, that Inilock was facing an existential threat to the company.They hadn't gained any new expertise in software development, so they hired another consulting firm, which is where Christian enters this story. His team was brought in to try and fix this disaster before Inilock locked their own doors for good.The first thing Christian did was track down the source control server and start reading through the code. The server was written in C#, and while the project started in 2018, every choice that was made was frozen someplace circa 2008- using ADO .NET for database access, instead of any of the more modern frameworks that .NET had added.That was annoying, but more telling was the release process. There was no CI/CD. A developer pulled the code, ran "Build..." on their local machine, and then uploaded the binary to an FTP server. Another tool could be run on the target network to grab the binary and distributed it to all the locks on that network.That gave Christian a sense of the overall care that went into the project, but it was when investigating the network protocol and how it was handled that he started to understand why using the software was such a terrible experience.The configuration application wrote records to an MS-SQL database. Another service queried that database periodically. When the data changed, it would broadcast out the new configuration to all the locks via a homegrown TCP protocol. It would read the data from the database, convert it to XML, blast the XML across a TCP socket to each client, and then query the database again, in an endless loop. Well, mostly endless.What the service didn't do was any sort of error handling. Oh, and it didn't insert any breaks in the stream, or give the client any way of knowing how long the stream of data it should be expecting.Every client just had a buffer, scanned the buffer every 50ms, and assumed that everything in the buffer was a single message from the server. This was fine in a laboratory environment where there was very little traffic or latency on the network, but in a real network the clients would frequently check the buffer before the entire message had arrived, or end up with two messages in the buffer. There was no error handling on the clients either, so they'd just hang on the bad data.And since the server wasn't doing any error handling, timeouts or any asynchronous messaging, it'd hang when enough of those connections went down.Ripping out the messaging layer and replacing it with fit-for-purpose 3rd-party library was a great deal of work, but that alone was enough to fix the reliability problems and boost performance of the system by 1000%. The architecture is still a ridiculous disaster, the UI is still a nightmare, there are still all sorts of bad choices, sources of crashes, and the only bits of the code base that have any automated tests are the ones which Christian's team touched. But it's gone from a massive trainwreck of toxic waste to a moderately sized trainwreck of toxic waste.Whether it's enough to save Inilock remains to be seen, but when Christian cashes his checks for being a consultant, he at least knows he made things better. [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 (#6F1VR)
Mike was refactoring an old web application written in Perl. We joke about Perl being a "write only language," but the original developer wanted to take that unreadable attitude to the JavaScript front-end portion of the application.
|
|
by Lyle Seaman on (#6EZV0)
This week we received a plethora of failed text substitutions. I'd like to find a pithyname for this sort of error; suggestions in the comments here will be welcomed.But before we dive into those typical errors, repeat contributor Valts S. has shared a classic blunder:"White text on white background. Who among us hasn't done this in our lives? :)"
|
|
by Remy Porter on (#6EYPH)
Typos are the bane of delevopers' existence. For most of our typos, the result is a syntax error. It's quick and easy to find and fix. But any time we're working with strings (or in languages where variables are declared at use) there can be many more subtle bugs.So when Abigail's company sent an intern off to fix a few typos, they thought this was a lovely little low-hanging fruit bug to fix.There were three typos which needed to be fixed.
|
|
by Remy Porter on (#6EXHP)
There are common errors that are (or were) once so common that we've built tools to help us avoid them. So I was a little surprised to see this JavaScript from Annie's co-worker.
|
|
by Remy Porter on (#6EWH4)
David's organization didn't fully understand why you bring interns into a company. The purpose of an internship is to provide an educational opportunity and resume line-item to someone looking to enter the industry, and possibly recruit said intern after they graduate, getting a new-hire that is more ready for your team than average. It's good for the intern, it's good for the overall health of the industry, it's good for the company building its network of professional relationships and recruiting opportunities.The purpose of an internship is not to just throw tickets at an intern, and let them commit code to your main branch, unsupervised. Unfortunately for David, and for the poor interns that preceded him, that is what the company had done.
|
|
by Remy Porter on (#6EVCZ)
Sometimes, you see a code sample and you almost scroll by. "This isn't bad, I see it all the time." So it took a second glance to see the awful charm of what Henrik H found.Henrik was asked to join a project to fix a high load website having "some issues". Here's a JavaScript tag that was included on nearly every page.
|
|
by Lyle Seaman on (#6ES9J)
From our readers this week, we have a couple of mixed numbers. David B even gets a twofer.Trainspotter Daniel notes "The LIRR now has the technology to pass 9 minutes with only 5 minutes of waiting!"They're apparently doing something nonobvious aboutscheduled versus expected times in one context, but notin another. Maybe the readers can figure it out.
|
|
by Remy Porter on (#6ERBD)
"John Doe" was asked to take a look at a slow-running application. It didn't take too long to discover that the application was slow because the database was slow, but figuring out why the database was slow involved digging deeply through some logs.The database was a central system, which many applications connected to. Every ten minutes, performance dropped significantly, and it just so happened that every ten minutes a batch update process ran.
|
|
by Remy Porter on (#6EQ6Q)
Moz works for a company that needs to handle financial transactions. They use Delphi, which has a handy-dandy fixed precision Currency type, which should make this easy.Of course, someone opted to do most of the math in double precision floating points anyway. Which lead to this function:
|
|
by Remy Porter on (#6EP64)
As frequently stated, concurrency is hard. Ensuring that all of your data is accessed in a threadsafe manner is a real challenge. So when Ryan saw a method called ThreadSafeArray, it seemed like an obvious utility method: wrap an array up in a thread safe accessor, right?Well, the signature of the function made Ryan suspicious. And the code...
|
|
by Remy Porter on (#6EN3Q)
Time zones are hard. And, to my surprise, if you want to enumerate all the time zones in the world in C#, there isn't an easy way to do that. You can enumerate all the time zones configured on the host computer (in Windows), but that may be incomplete and also may use idiosyncratic names, since it doesn't use the IANA database of timezones.This leaves developers with a three real options. The first would be to either load the IANA database yourself, and the second would be to use a library that provides it.Which, Louis's team did the first- they maintained a time zone database in their application database that contained all the time zones, in their canonical names.Or, I should say, most of Louis's team did the first. One developer found the third option. They didn't use the database. They didn't use a library. They just hard-coded all the options into the UI:
|
|
by Lyle Seaman on (#6EJPF)
Joseph H. is a little salty about vapid adverts. "Vacation planners long ago figured out that the GreatSalt Lake didn't make for great resorts.They must be referring to the up-and-coming land cruisesacross the desert plains of Utah. Definitely that. Noother possible explanation."
|
|
by Remy Porter on (#6EHGG)
The easiest way to write programs that support concurrency is to not. JavaScript in the browser is famously single-threaded, unless you add web-workers, which have a very specific way of interacting with your main script that avoids most of the pitfalls of concurrency. Or at least makes them easy to avoid.But what if you had a developer who didn't know any of this, and just assumed JavaScript was multithreaded and needed locks, but didn't understand how locks worked? Then you'd get something like this code, from an anonymous submitter.
|
|
by Remy Porter on (#6EGCF)
A decade ago, Adam was doing support on a classic ASP application. This was an internal application which tracked sales accounts, employee reviews, and general HR information. Now, the company had a real HR system, but some of their internal processes predated the HR system, thus they had a custom application that did things the HR system already did, but they already owned the application and didn't want to retrain people.One day, a manager logged in, started doing some work, took a break, and came back, only to discover that when she pulled up a list of employees, she no longer saw her direct reports, but instead saw all of the employees at the company. She reported the bug and Adam picked up the ticket.Adam's first suspicion was that her session timed out, and then there must be something wrong in how the session got initialized.
|
|
by Remy Porter on (#6EFF3)
Tracking the performance of an application matters. Too often, developers will try and tune and optimize an application based on their instincts about where the performance is bad- instincts which are frequently wrong.Remy L's company included performance tracking blocks in their code, enabled by a debug flag. According to the performance stats, their program performed incredibly well. There were rarely ever any long-running methods.Unfortunately, these wonderful statistics didn't jive with the experience of the users, who would often wait thirty seconds to a minute for the application to respond after clicking a button.And also, as one weird thing, the performance monitor sometimes reported that methods took negative amounts of time to execute, making this program fast enough to break the laws of time and space.Why was there such a difference?
|
|
by Remy Porter on (#6EEDH)
|
|
by Lyle Seaman on (#6EC8B)
We had to stretch just a little bit to make a purelyMicrosoft-themed column this week. Gone are the days when it was trivial to make BSOD jokes and rail at OutlookExpress. But they still give us material for some lolz now and then.Well-rested reader Michael W.remarks "After waking up my laptop from a long period of slumberand logging in I am greeted by the attached error messageon my desktop: You'll need the Internet for this.Which makes me wonder what do I need the internet for?The dialog has no title and it's not clear if it's connectedto any other open windows. Whatever the ''this'' is supposedto reference to stays shredded in mystery providing no contextwhatsoever. But I guess it's at least a step up from those''Internal Error'' message dialogues.And yes, of course a solution can be googled for, but alas mostof those pages will tell you how to fix a network connectionproblem but also mostly won't tell you to what applicationor use this dialogue relates to (apparently it's Windows 365 subscription related)"
|
|
by Remy Porter on (#6EB3N)
When your program needs to pause, there are several options. The first is a pure busy loop- usually a bad idea, but frequently more efficient for very short delays than other options. The "standard" is to sleep your program- just tell the OS scheduler to let other programs run and to wake you up after some interval. In multithreaded programs, you'll frequently sleep one thread while waiting on others.Which is what Cisco's co-worker sort of did. Sort of.
|
|
by Remy Porter on (#6E9ZN)
Over 15 years, an intranet application with a small userbase has gradually become "mission critical". The original developers and all of the maintainers have been folks who didn't have any software development experience, beyond "I took a bootcamp once ten years ago" and "I can do Excel macros". At least they didn't 15 years ago, but over the past 15 years, it's turned into some people's full time job.Krister E. was hired to try and turn this into a mature software product that didn't require constant babysitting and tending to keep it from crashing, burning, exploding, and leaving a cloud of fallout behind it. There were some challenges to that.
|
|
by Remy Porter on (#6E8TS)
When Allan C's company, Initrode, got acquired by Initech a few years ago, it sounded like actually good news for the rank and file employees. Initech had a product in the same line of business as Allan's employer, and it was better in most ways, at least according to customer feedback. Allan's team had built some features into their product that Initech wanted, and Initech was also looking to grow rapidly, so there was no fear of layoffs. In fact everybody got a mild raise, and only a few middle managers were asked to leave the company.That's about where the good news ended.Initech built their product in JavaScript, but they had frozen their codebase on a version of the JavaScript runtime from the early 2000s. For Allan, who had been doing modern JavaScript for pretty much his entire career, this was like going back to stone tools. The code had few attempts at modularization- some of the code had the courtesy to create its local variables in an immediately invoked function expression, which was how one did modules before modules existed, but most of the code just slapped variables and functions into the global namespace and hoped for the best.That made the code difficult to debug, as there were loads of unintended side effects- side effects that frequently resulted in exceptions. Fortunately, all the exceptions were caught... somewhere. Frequently they were caught, handled, then a new exception was thrown with a different error message.Now, that might sound like it makes it difficult to understand the causes of exceptions, as if you're throwing entirely new exceptions, you're destroying the stack trace information. But you have to remember this was a JavaScript was an antique: exceptions didn't have stack trace information.Also making things difficult to debug: there wasn't a debugger. Your solution to tracing through the code was putting a lot of print statements into it, and trying to understand the output.One day, while bashing his head up against a particularly thorny bug and wishing for some sort of useful stack trace information, Allan had an idea. Since all the important functions were already in the global namespace, it wouldn't be hard to write some JavaScript that wrapped every function with some debugging and tracking behavior. Since the runtime didn't provide a stack trace, he could wrap every function and build a stack trace as they were invoked. And when an error happened, he could log it at the level where it happened, and not need to put print statements everywhere.As solutions go, it was cumbersome and hacky, but it was better than anything else Allan had available to him. The thorny bug that Allan was fighting with became trivial to fix once he could see the stack trace and the source of the errors.In coffee-maker and water-cooler conversations, Allan hinted at his great new tool, but no one else expressed any interest in what he was working on. So, he plotted out a demo. He created a simulated use case- he inserted a bug into a module that he thought would be difficult to find. He ran the code, and got an error message: "Found an error in the column module foo"."Great," Allan said. "So how would we track this error down?" Allan was feeling pretty clever at this moment, as there were dozens of "column module" types, so tracking down the actual source would be rather difficult.Gary, the original architect of the code base and resident curmudgeon said, "Just search through the code base for the error message."Allan felt stupid- he hadn't planned for that specific solution. He hadn't considered that the error message might be unique enough to find a specific file. Unfortunately, the first result was the file he'd modified. "Uh, yeah, let's... um... check that."Allan added a print statement to the file. If Gary had found the bug, it would print a "Found it!" message, and no one would ever want to use Allan's tool. Allan re-ran the program. The "Found it!" message didn't appear.Everyone was shocked, especially Allan. Gary was wrong? But so was Allan? There was only one way to figure out what was really going on: use Allan's debugging tool. He loaded up the tool, re-ran the program, and within seconds was able to pinpoint exactly what was going on.While their search had turned up the first instance of "Found an error in the column module foo", there were several more. As it turned out, the place where Allan had inserted the bug was actually in "Column Module Bar"- which itself was just a copy/paste of "Foo", with minor modifications.Allan was overjoyed. For a moment, his demo teetered on the edge of catastrophe, and then his own errors highlighted how easy it was to make mistakes in this codebase, and how quickly his tool could help diagnose them. He highlighted the line containing the bug, and waited for the accolades from the team for being so very, incredibly clever."Maybe," Gary said, "instead of wasting time with your tool, we should just fix the error message." He typed for a few moments, and then said, "There. Pushed a fix. Can we get back to work now, or do you have more ways to waste our time?"It was at that moment Allan realized the code wasn't accidentally terrible, it was intentionally terrible. It was the way it was because Gary wanted it that way, and Gary wasn't going to let it be any better than it was, no matter what Allan did.Allan was the first of the Initrode team to abandon ship, but he wasn't the last. And once the first wave of experienced, senior talent started jumping ship, things quickly got worse for everyone remaining, and they jumped ship too. Within a year, everyone was gone except for Gary and a pile of junior developers too inexperienced to know how bad their working environment was.Allan's debugging tool is likely still somewhere in their source control repository, collecting digital dust, and waiting for one of those junior developers to discover it. [Advertisement] ProGet's got you covered with security and access controls on your NuGet feeds. Learn more.
|