by Remy Porter on (#5QTYM)
When someone mentioned to Abraham, "Our product has an auto-sync feature that fires every hour," Abraham wasn't surprised. He was new to the team, didn't know the code well, but an auto-sync back to the server sounded reasonable.The approach, however, left something to be desired.
|
The Daily WTF
Link | http://thedailywtf.com/ |
Feed | http://syndication.thedailywtf.com/TheDailyWtf |
Updated | 2024-11-22 01:16 |
by Lyle Seaman on (#5QR4H)
Two of today's ticklers require a little explanation, while the others require little.Kicking things off this week, an anonymous reporter wants tokeep their password secure by not divulging their identity. It won't work,that's exactly the same as my Twitch password."Twitch seems to be split between thinking whethermy KeePass password is strong or not," they wrote.Explanation: The red translates to "This password is too easy to guess",while the green 'Stark' translates as "you've chosen a very good passwordindeed."
|
by Remy Porter on (#5QPV8)
Using built-in methods is good and normal, but it's certainly boring. When someone, for example, has a list of tags in an array, and calls string.Join(" ", tags), I don't really learn anything about the programmer as a person. There's no relationship or connection, no deeper understanding of them.Which, let's be honest, is a good thing when it comes to delivering good software. But watching people reinvent built in methods is a fun way to see how their brain works. Fun for me, because I don't work with them, probably less fun for Mike, who inherited this C# code.
|
by Remy Porter on (#5QNR5)
Starting in the late 2000s, smartphones and tablets took off, and for a lot of people, they constituted a full replacement for a computer. By the time the iPad and Microsoft Surface took off, every pointy-haired-boss wanted to bring a tablet into their meetings, and do as much work as possible on that tablet.Well, nearly every PHB. Lutz worked for a company where management was absolutely convinced that tablets, smartphones, and frankly, anything smaller than the cheapest Dell laptop with the chunkiest plastic case was nothing more than a toy. It was part of the entire management culture, led by the CEO, Barry. When one of Lutz's co-workers was careless enough to mention in passing an article they'd read on mobile-first development, Barry scowled and said "We are a professional software company that develops professional business software."Back in the mid 2010s, their customers started asking, "We love your application, but we'd love to be able to access it from our mobile devices," Barry's reply was: "We should support standards. The standard is Microsoft Windows.""Oh, but we already access your application on our mobile devices," one of the customers pointed out. "We just have to use the desktop version of the page, which isn't great on a small screen."Barry was livid. He couldn't take it out on his customers, not as much as he wanted to, but he could "fix" this. So he went to one of his professional software developers, at his professional software company, and asked them to professionally add the following check to their professional business software:
|
by Remy Porter on (#5QMA5)
Duncan B was contracting with a company, and the contract had, up to this point, gone extremely well. The last task Duncan needed to spec out was incorporating employee leave/absences into the monthly timesheets."Hey, can I get some test data?" he asked the payroll system administrators."Sure," they said. "No problem."
|
by Remy Porter on (#5QK4R)
Russell F has an object that needs to display prices. Notably, this view object only ever displays a price, it never does arithmetic on it. Specifically, it displays the prices for tires, which adds a notable challenge to the application: not every car uses the same tires on the front and rear axles. This is known as a "staggered fitment", and in those cases the price for the front tires and the rear tires will be different.The C# method which handles some of this display takes the price of the front tires and displays it quite simply:
|
by Lyle Seaman on (#5QG8G)
... and gigs for free."Apple is magical," rhapsodizes music-lover Daniel W.
|
by Remy Porter on (#5QES2)
I recently started a new C++ project. As it's fairly small and has few dependencies, I made a very conscious choice to just write a shell script to handle compilation. Yes, a Makefile would be "better", but it also adds a lot of complexity my project doesn't need, when I can have essentially a one-line build command. Still, my code has suddenly discovered the need for a second target, and I'll probably migrate to Makefiles- it's easier to add complexity when I need it.Kai's organization transitioned from the small shell-scripts approach to builds to using Makefiles about a year ago. Kai wasn't involved in that initial process, but has since needed to make some modifications to the Makefiles. In this case, there's a separate Makefile for each one of their hundreds of microservices.Each one of those files, near the top, has this:
|
by Remy Porter on (#5QD95)
This past Monday, Facebook experienced an outage which lasted almost six hours. This had rattle-on effects. Facebook's pile of services all failed, from the core application to WhatsApp to Oculus. Many other services use Facebook for authentication, so people lost access to those (which highlights some rather horrifying dependencies on Facebook's infrastructure). DNS servers were also strained as users and applications kept trying to find Facebook, and kept failing.CloudFlare has more information about what went wrong, but at its core: Facebook's network stopped advertising the routes to its DNS servers. The underlying cause of that may have been a bug in their Border Gateway Protocol automation system:
|
by Remy Porter on (#5QBSR)
When you promise to deliver a certain level of service, you need to live up to that promise. When your system is critical to your customers, there are penalties for failing to live up to that standard. For the mission-critical application Rich D supports, that penalty is $10,000 a minute for any outages.Now, one might think that such a mission critical system has a focus on testing, code quality, and stability. You probably don't think that, but someone might expect that.This Java application contains a component which needs to take a zip file, extract an executable script from it, and then execute that script. The code that does this is… a lot, so we're going to take it in chunks. Let's start by looking at the core loop.
|
by Jane Bailey on (#5QABQ)
The year was 2015. Erik was working for LibCo, a company that offered management software for public libraries. The software managed inventory, customer tracking, fine calculations, and everything else the library needed to keep track of their books. This included, of course, a huge database with all book titles known to the entire library system.Having been around since the early 90s, the company had originally not implemented Internet connectivity. Instead, updates would be mailed out as physical media (originally floppies, then CDs). The librarian would plug the media into the only computer the library had, and it would update the catalog. Because the libraries could choose how often to update, these disks didn't just contain a differential; they contained the entire catalog over again, which would replace the whole database's contents on update. That way, the database would always be updated to this month's data, even if it hadn't changed in a year.Time marched on. The book market grew exponentially, especially with the advent of self-publishing, and the Internet really caught on. Now the libraries would have dozens of computers, and all of them would be connected to the Internet. There was the possibility for weekly, maybe even daily updates, all through the magic of the World Wide Web.For a while, everything Just Worked. Erik was with the company for a good two years without any problems. But when things went off the rails, they went fast. The download and update times grew longer and longer, creeping ever closer to that magic 24-hour mark where the device would never finish updating because a new update would be out before the last one was complete. So Erik was assigned to find some way, any way, to speed up the process.And he quickly found such a way.Remember that whole drop the database and replace the data thing? That was still happening. Over the years, faster hardware had been concealing the issue. But the exponential catalogue growth had finally outstripped Moore's Law, meaning even the newest library computers couldn't keep up with downloading the whole thing every day. Not on library Internet plans.Erik took it upon himself to fix this issue once and for all. It only took two days for him to come up with a software update, which was in libraries across the country after 24 hours. The total update time afterward? Only a few minutes. All he had to do was rewrite the importer/updater to accept lists of changed database entries, which numbered in the dozens, as opposed to full data sets, which numbered in the millions. No longer were libraries skipping updates, after all.Erik's reward for his hard work? A coupon for a free personal pizza, which he suspected his manager clipped from the newspaper. But at least it was something. [Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!
|
by Lyle Seaman on (#5Q79J)
This week's installation of Error'd includes a few submissionswhich honestly don't seem all that WTFy. In particular, this firstone from the unsurnamed Steve. I've included it solely so I can pedantically proclaim "24 is not between 1 and 24!"There is still a wtf here though. What is withthis error message?Insufficiently pedantic Steve humorlessly grumbles"Configuring data pruning on our Mirth Integration Engine.Mirth can do many things, just can't count up to 24."
|
by Remy Porter on (#5Q5S2)
Like a lot of HR systems, the one at Initech had grown into a complicated mess of special cases, edge cases, and business rules that couldn't be explained but had to be followed.Mark was assigned to a project to manage another one of those special cases: Initech had just sold one of its factories. Their HR system needed to retain information about the factory and its employees up until the point of the sale, but it also needed to be disconnected from some future processing- they certainly didn't want to send anybody any paychecks, for example. But not all processing. If an employee had started a health insurance claim before the factory was sold, they needed to keep that active in the system until it was completed (but also not allow the employee to file new claims).It was going to be a lot of special processing, so Mark made a simple suggestion: "Why don't we add a 'sold' checkbox, or a 'decommissioned' flag, or something like that? We add that as a data-field to a factory, and then we know all employees associated with that factory go down a different processing path.""Oh, we can't do that," Mark's boss, Harlan, countered. "It would be a new database field, changes to the factory edit screen, we'd have to document it for the users, probably add an 'are you sure' confirmation dialog, it's just too much work to do that and then also add all the special processing rules."It was okay, though, because Harlan had a simpler solution. Just do the special processing rules. IF factory_id == 27 THEN doTheSoldFactoryStuff() ELSE doTheRegularFactoryStuff(). No changes to the database, no changes to any screens, they just had to go through thousands of lines of code, scattered across hundreds of different modules and individual programs, and jam that special branch in there, in the right spot."Right," Mark cautioned, "but the next time we sell a factory, we'll have to do this all over again. Whereas if we add the checkbox-""How often do you think we're going to be selling factories? It's fine," Harlan said.The next six months were the tedious process of going through all the places in the software where the special branch needed to go. Of course, no one was precisely documenting this, no one was really concerning themselves with any minutae like a "clean commit history": patch the code, maybe add a comment, and move on with your day. And it's not the case that every place they were changing the code fit exactly that pattern of IF factory_id == 27; not every system used the same naming conventions, or even the same language.It was a rough six months, but at the end of it, the factory was sold, the HR systems processed everything correctly, and management was happy with the end result. There was just one more thing…"Welp," Harlan said as he called everyone in for the new project kickoff. "We've sold another factory, and I have a plan for how we're going to make that change, without needing to add any database fields or modify any UI elements."As Camus said, "One must imagine Sisyphus happy," but Mark was significantly less happy. If Harlan had taken his input, this wouldn't be an IT task at all. As it was, Mark had a good sense of what the next six months of work was going to look like. [Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.
|
by Remy Porter on (#5Q4B7)
A surprising amount of the world runs on FORTRAN. That's not to say that huge quantities of new FORTRAN are getting written, though it's far from a dead language, but that there are vital libraries written fifty years ago that are still used to this day.But the world in which that FORTRAN was written and the world in which we live today is wildly different. Which brings us to the story of George and Ike.In the late 1960s, the company that Ike worked for got a brand-spanking new CDC 6600 mainframe. At the time, it was the fastest computer you could purchase, with a blistering 3MFLOPS performance- 3 million floating point operations per second. The company wanted to hand this off to their developers to do all sorts of fancy numerical simulations with FORTRAN, but there was just one problem: they wanted to do a lot of new programs, and the vendor-supplied compiler took a sadly long time to do its work. As they were internally billing CPU time at $0.10/second, teams were finding it quite expensive to do their work.
|
by Remy Porter on (#5Q2TC)
Indirection is an important part of programming. Wrapping even core language components in your own interfaces is sometimes justifiable, depending upon the use cases.But like anything else, it can leave you scratching your head. Sam found this bit of indirection in a NodeJS application:
|
by Remy Porter on (#5Q1E8)
John H works with some industrial devices. After a recent upgrade at the falicity, the new control software just felt like it was packed with WTFs. Fortunately, John was able to get at the C# source code for these devices, which lets us see some of the logic used…
|
by Lyle Seaman on (#5PYA2)
One of this week's entries is the type that drives me buggy. Guess which one.Regular contributorPascal splains this shopping saga:"Amazon now requires anti-virus software to have an EPARegistration number."
|
by Remy Porter on (#5PWTK)
As developers, we often have to engage with management who doesn't have a clue what it is we do, or how. Even if that manager was technical once, their technical background is frequently out of date, and their spirit has been sapped by the endless meetings and politics that being a manager entails. And it's often these managers who have some degree of control over where our career is going to progress, so we need to make them happy.Which means… <clickbait-voice>LEVEL UP YOUR CAREER WITH THIS ONE SIMPLE TRICK!</clickbait-voice>. You need to make managers happy, and if there's one thing that makes managers happy, it's dashboards. Take something complicated and multivariate, and boil it down to a simple system. Traffic lights are always a favorite: green is good, red is bad, yellow is also bad.It sounds stupid, because it is, but one of the applications that got me the most accolades was a dashboard application. It was an absolute trainwreck of code that slurped data from a dozen different silos and munged it together via a process the customer was always tweaking, and turned the complicated mathematics of how much wasteage there was in an industrial process into a simple traffic light icon. Upper managers used it and loved it, because that little glowing green light gave them all the security they needed, and when one of those lights went yellow or worse, red, they could swoop in and do management until the light turned green again.Well, Kaspar also supports a dashboard application. It also slurps giant piles of data from a variety of sources, and it tries to turn some key metrics into simple letter grades- "A" through "E".This particular query is about 400 lines of subqueries connected via LEFT JOIN. The whole thing is messy in the way that only giant SQL queries that are trying to restructure and reshape data in extreme ways can be. That's not truly a WTF, but several of these subqueries do something… special.
|
by Remy Porter on (#5PVBM)
When you're a large company, like Oracle, you can force your customers to do things your way. "Because we said so," is something a company like that can get away with. Conversely, a small company is more restricted- you have to work hard to keep your customers happy.When Doreen joined Initech, they were a small company with a long history and not too many customers. In the interests of keeping those customers happy, each customer got their own custom build of the software, with features tailored to their specific needs. So, Initrode was on "INITRODE.9.1", while the Soggy Beans coffee shop chain was on "SOGGY.5.2". Managing those versions was a pain, but it was Doreen's boss, Elliot, who ensured that pain escalated to anguish.Elliot was the one who laid out their software development and source control processes. It was the Official Process™, and Elliot was the owner of the Official Process™. The Official Process™ was the most elegant solution Elliot could imagine: each version lived in its own independent Subversion repository. Changes were synced between those repositories manually. Releases were also manual, and rare. Automated testing was non-existent..Upper management may not have understood the problems that created, but they knew that their organization was slow to release new features, and that customers were getting frustrated with poor response times to bugs and feature requests. So they went to the list of buzzwords and started pushing for "Agile" and "DevOps" and "Continuous Delivery".Suddenly, Doreen and the other developers were given a voice. They pushed to adopt Git, over Subversion. "I've looked into this," Elliot said, "and it looks like Git uses GitHub and stores our code off-site. I don't trust things that are off-site. I want our code stored here!""No, you don't have to use GitHub," Doreen explained. "We can host our own server- I've been playing around with GitLab, which I think will fit our needs well."Elliot grumbled and wandered off.Doreen took a few hours to configure up a GitLab instance, and migrate their many versions of the same code into something approaching a sane branching structure. It'd be a lot of work before the history actually made any sense, but it allowed her to show off some of the benefits, like that it would build and run the handful of unit tests she whipped up on commits to certain branches."That's fine," Elliot said, "but where's the code?""What… do you mean? It's right here.""That's the code for Soggy Beans, where's the Initrode version?" Elliot demanded.Doreen switched branches. "Right here.""But where did the Soggy Beans version go?!" Elliot was getting angry."I… don't understand? It's stored in Git. We're just changing branches.""I don't like this magical nonsense. I want to see our code in folders, as files, not this invisible shapeshifting stuff! I don't want our code where I can't see it!"Doreen attempted to explain what branches were, about how Git stored files and tracked versions, but Elliot was already storming off to raise hell with the one upper manager who still listened to him. And a few days later, Elliot came back with a plan."So, since we're migrating to Git," Elliot explained to the team, "that poses a few challenges, in terms of the features it lacks. So I've written a script that will supplement it."The script in question enumerated all the branches and tags in the repository, checked each one out in turn then copied it to another folder. "Once you've run this, you can navigate to the correct folder and make your changes there. If you need to make changes that impact multiple customers, you can repat those changes on each folder. Then you can run this second script, which will copy the changed folders back to the repository and commit it." This was also how code would be deployed: explode the repository out into folders, and copy the appropriate folder to the server.At first, Doreen figured she could just ignore the script and do things the correct way. But there were a few problems with that. First, Elliot's script created commits that made it look like every file had been changed on every commit, making history meaningless. Second, it required you to be very precise about which branches/versions you were working on, and it was easy to make a mistake and commit changes from one branch into another, which was a mistake Elliot made frequently. He blamed Git for this, obviously.But third, and most significantly: Elliot's script wasn't a suggestion. It was the Official Process™, and every developer was required to use it. Oh, you could try and "cheat", but your commits would be clean, clear, and comprehensible, which was a dead giveaway that you weren't following the Official Process™.Doreen left the company a short time later. As far as anyone knows, Elliot still uses his Official Process™. [Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!
|
by Remy Porter on (#5PSSY)
When Daniel was young, he took one of those adventure trips that included a multi-day hike through a rainforest. At the time, it was one of the most difficult and laborious experiences he'd ever had.Then he inherited an antique PHP 5.3 application, written by someone who names variables like they're spreadsheet columns: $ag, $ah, and $az are all variables which show up. Half of those are globals. The application is "modularized" into many, many PHP files, but this ends up creating include chains tens of files deep, which makes it nigh impossible to actually understand.But then there are lines like this one:
|
by Remy Porter on (#5PRAY)
Last week, we saw some possibly ancient Pascal code. Leilani sends us some more… modern Pascal to look at today.This block of code comes from a developer who has… some quirks. For example, they have a very command-line oriented approach to design. This means that, even when making a GUI application, they want convenient keyboard shortcuts. So, to close a dialog, you hit "CTRL+C", because who would ever use that keyboard shortcut for any other function at all? There's no reason a GUI would use "CTRL+C" for anything but closing windows.But that's not the WTF.
|
by Lyle Seaman on (#5PN46)
We generally don't like to make fun of innocentmisuses of a second language. Many of us strugglewith their first. But sometimes we honestly can'ttell which is first and which is zeroeth.Whovianstombaker pontificates"Internationalization is hard.Sometimes, some translations are missing, someother times, there are strange concatenationsdue to language peculiarities. But here, we haveeverything wrong and no homogeneity in the issues."
|
by Remy Porter on (#5PKVQ)
Back in the mid-2000s, Maurice got less than tempting offer. A large US city had hired a major contracting firm, that contracting firm had subcontracted out the job, and those subcontractors let the project spiral completely out of control. The customer and the primary contracting firm wanted to hire new subcontractors to try and save the project.As this was the mid-2000s, the project had started its life as a VB6 project. Then someone realized this was a terrible idea, and decided to make it a VB.Net project, without actually changing any of the already written code, though. That leads to code like this:
|
by Remy Porter on (#5PJDN)
We've got a lovely backlog of short snippets of code, and it's been a long time since our last smorgasbord, so let's take a look at some… choice cuts.Let's open with a comment, found by Russell F:
|
by Remy Porter on (#5PGYV)
The HP3000 was the first mini-computer that supported time-sharing. It launched in 1972, and HP didn't end-of-life it until 2010, and there are still third-party vendors supporting them.Leonora's submission is some code she encountered a number of years ago, but not as many as you might think. It's in Pascal, and it's important to note that this version of Pascal definitely has bitwise operators. But, if you're programming on a 40 year old minicomputer, maybe you couldn't do an Internet search, and maybe Steve from down the hall had bogarted the one manual HP provided for the computer so you can't look it up because "he's using it for reference."So you end up doing your best with no idea:
|
by Remy Porter on (#5PFKD)
When evaluating a new development tool or framework, the first thing the smart developer does is check out the vendor documentation. Those docs will either be your best friend, or your worst enemy. A great product with bad documentation will provide nothing but frustration, but even a mediocre product with clean and clear documentation at least lets you get useful stuff done.Stuart Longland's company has already picked the product, unfortunately, so Stuart's left combing through the documentation. This particular product exposes a web-socket based API, and thus includes JavaScript samples in its documentation. Obviously, one could use any language they like to talk to web-sockets, but examples are nice…
|
by Lyle Seaman on (#5PCFA)
Despite literally predating paper, passcodes and secret handshakescontinue to perplex programmers, actors, and artists alike.For our first example, auteurAndy stages a spare play in three acts.
|
by Remy Porter on (#5PB4W)
Dave inherited a data management tool. It was an antique WinForms application that users would use to edit a whole pile of business specific data in one of those awkward "we implemented a tree structure on top of an RDBMS" patterns. As users made changes, their edits would get marked with a "pending" status, allowing them to be saved in the database and seen by other users, but with a clear "this isn't for real yet" signal.One developer had a simple task: update a text box with the number of pending changes, and if it's non-zero, make the text red and boldfaced. This developer knew that some of these data access methods might not return any data, so they were very careful to "handle" exceptions.
|
by Remy Porter on (#5P9M9)
Today's submitter goes by "[object Object]", which I appreciate the JavaScript gag even when they send us C code.This particular bit of C code exists to help output data in fixed-width files. What you run into, with fixed-width files, is that it becomes very important to properly pad all your columns. It's not a difficult programming challenge, but it's also easy to make mistakes that cause hard-to-spot bugs. And given that most systems using fixed-width files are legacy systems with their own idiosyncrasies, things could easily go wrong.Things go more wrong when you don't actually know the right way to pad strings. Thus this excerpt from constants.h.
|
by Remy Porter on (#5P83M)
Shalonda inherited a C# GUI application that, if we're being charitable, has problems. It's slow, it's buggy, it crashes a lot. The users hate it, the developers hate it, but it's also one of the core applications that drives their business, so everyone needs to use it.One thing the application needs to do is manage a list of icons. Each icon is an image, and based on user actions, a new icon might get inserted in the middle of the list. This is how that happens:
|
by Remy Porter on (#5P72Z)
|
by Lyle Seaman on (#5P457)
Testing in production again, here's five fails for the fifth day of the week. Or the sixth. Or is it the fourth?Anonymous Ignoronymous declares "Dude! Science tests were never popular!"
|
by Remy Porter on (#5P2NZ)
Despite being a programmer, I make software that goes in big things, which means that my workplace frequently involves the operation of power tools. My co-workers… discourage me from using the power tools. I'm not the handiest of people, and thus watching me work is awkward, uncomfortable, and creates a sense of danger. I'm allowed to use impact drivers and soldering irons, but when it comes time to use some of the more complex power saws, people gently nudge me aside.There are tools that are valuable, but are just dangerous in the hands of the inexperienced. And even if they don't hurt themselves, you might end up boggling at the logic which made them use the tool that way. I'm talking, of course, about pre-compiler macros.Lucas inherited some C++ code that depends on some macros, like this one:
|
by Remy Porter on (#5P15Q)
When moving from one programming language to another, it's easy to slip into idioms that might be appropriate in one, but are wildly out of place in another. Tammy's company has some veteran developers who spent most of their careers developing in COBOL, and now' they're developing in C#. As sufficiently determined programmers, they're finding ways to write COBOL in C#. Bad COBOL.Methods tend towards long- one thousand lines of code isn't unusual. Longer methods exist. Every method starts with a big long pile of variable declarations. Objects are used more as namespaces than anything relating to object-oriented design. So much data is passed around as 2D arrays, because someone liked working with data like it lived in a table.But this method comes from one specific developer, who had been with the company for 25+ years. Tammy noticed it because, well, it's short, and doesn't have much by way of giant piles of variables. It's also, in every way, wrong.
|
by Remy Porter on (#5NZNH)
Sometimes, we get a submission and the submitter provides absolutely no context. Sometimes, the snippet is even really short, or the problem is "subtle" in a way that means we can't spot it when skimming the inbox.Which is why this submission from "Bus Error" has been sitting in the inbox for seven years, and why just today, as I was skimming old submissions, I finally saw what was great about this little block of C-code.
|
by Remy Porter on (#5NYBQ)
One of the biggest challenges in working with financial data is sanitizing the data into a canonical form. Oh, all the numeric bits are almost always going to be accurate, but when pulling data from multiple systems, is the name "John Doe", "John Q. Doe", "J. Doe"? What do we do when one system uses their mailing address and another uses their actual street address, which might use different municipality names? Or in all the other ways that important identifying information might have different representations.This is Andres' job. Pull in data from multiple sources, massage it into some meaningful and consistent representation, and then hand it off to analysts who do some capitalism with it. Sometimes, though, it's not the data that needs to be cleaned up- it's the code. A previous developer provided this Visual Basic for Applications method for extracting first names:
|
by Lyle Seaman on (#5NV82)
No real theme this week, just a handful of whoopses, culminating in a whoopsiedaisytopsyturvysuperduper huh?Excited Python fanAdam B. sneaks in some low-key publicity for the 3.10 release, saying "The community is so excited about the upcoming3.10 release, they ensured that everyone notices theannouncement."
|
by Remy Porter on (#5NSVV)
Steffen is the tech lead for an online shop. It's the kind of online shop that sell items with large enough prices that financing is an important function. They offer loans through a payment provider, and the payment provider handles all of the details.Anything relating to finance is complicated, and loans can get very complicated, especially these shorter-term loans. Generating a payment plan for a customer's order means creating a list of all the expected monthly installments, including the due dates, the remaining principal on the loan after the payment, how much goes to principal repayment, how much goes to interest, and the new balance of the loan after interest is added. It's a lot of information, and it's information that the payment provider can provide.But, in the interests of keeping their application responsive when providing a potential payment plan to their end user, Steffen's company opted to implement their own financial calculations. For actual payment handling, they'd still let the payment provider handle it, but for showing the customer "if you order now, this is what your payment plan will look like!", they could do that all on their side.Or could they? While it's complicated to calculate out all the loan elements, it's also well understood. There are libraries for it, there are copy/pasteable code snippets for it. It was complicated, but not hard.After ten days of effort, however, it wasn't working. Their test plan was simple: since the payment provider was the source of truth, they generated 10,000 sample payment plans. They fed those plans into their system, then into the payment provider's system, and then compared the results. And the results mostly matched. Mostly.There were a handful of test cases that were off by hundreds of Euros. That was way too much. Steffen called a meeting with the payment provider's technical staff, and developers from both companies sat down to go through the code, line by line.It was a long, tedious meeting, and while questions were raised about the varying implementations, by the end of the meeting, both companies agreed: the code was correct. But the output was wrong. The meeting ended with nothing resolved.So Steffen grabbed one of the developers, and they sat down to go through the test cases. They chose the one which had the largest deviation from the payment provider's values, and walked through each month of the payment plan.On the first month, both Steffen's code and the payment provider were in perfect agreement. But on the second month, Steffen's code said it was €932.28, while the payment provider said that it was €631.54. That was more than €300 off. But on the third month, things got weirder: the payment provider's plan said that the amount of interest owed went up. Loans don't work that way: as you pay the principal, the amount of interest you pay each month goes down. "Do you think they got it wrong?" Steffen wondered.It seemed promising, but then Steffen looked at the results in more detail. They had generated 10,000 random sample loans. This included random dates ranging from antiquity all the way out to the 30th century. It was very thorough testing.This particular loan's first due date was October 1st, 1582. When Steffen spotted that, he laughed and turned to the developer. "This is a joke, right?" When the developer didn't see the humor, Steffen explained.You see, Steffen didn't start life as a software developer. Before moving into the industry, he worked as a professional historian. And October 1582 was a very special month in history. A unique point in history: it was the month the Western world shifted from the Julian calendar to the Gregorian calendar.The Julian calendar assumed a year was exactly 365.25 days, which is not correct. Following that rule adds an extra leap day roughly every century. The Gregorian calendar was more precise, and mostly accurate about such thing. But to shift calendars, the Greogrian calendar needed to be synced with the seasons. That meant removing a few centuries worth of extra days left over from the Julian calendar. Call it "paying down calendrical debt". So, October 4th, 1582 was followed by October 15th, 1582. Ten days just vanished, and October 1582 had only 21 days in it.The payment provider's calendar system handled this perfectly well. Steffen's calendar system did not. That explained why they over-charged for October, and it also explained why it seemed like the interest payment went up- November 1582 was a normal, 30-day November.Since they would never be originating loans in the 16th century, Steffen's team generated a new set of test data, all after the start of the 21st century. This solved the problem, and after fixing a few minor bugs, their implementation matched the payment provider's.In the end, the Pope removed ten days from October 1582, and Steffen's team put them back, spending almost exactly that time on fixing this bug. [Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.
|
by Remy Porter on (#5NRD1)
"When handling user input, make sure to handle exceptions," is good advice. But sometimes, that can lead you astray.Bob is a junior programmer surrounded by veterans with 20+ years of experience. Normally, this means that when there's something unusual in the code, Bob writes it off as the senior devs vast experience. But not this time.
|
by Remy Porter on (#5NPVG)
Yesterday, among many many problems in that gigantic switch statement, we highlighted one line that was a real mess of mixing Java's primitive/object types.(new Integer(1).equals(job.getSource().getLength()))Well, Daniel has an even worse example, but this one comes with an origin story.Many, many years ago, in the early 2000s, Daniel worked for a company that made banking software. As this was the early 2000s, their flagship product remained a text-based UI accessed via a terminal emulator (or, in some rare cases, even dumb terminals). Obviously, continuing this TUI approach wasn't going to work in the future, so the company needed to pivot to a Java-based web application.The CEO set the direction: "We need a modern, web-based interface to sell banks. How much would it cost to implement that?" Well, Daniel's team put together the estimate, which contained a large number of trailing zeroes before the decimal point. Too many, from the CEO's perspective, so the CEO went shopping for a third-party developer who could deliver the software on the cheap.Again, this was the early 2000s, which meant the CEO was filtering through a dozen different obscure offshoring companies. The CEO wasn't impressed by most of them, but one offshore company came to the meeting with a wireframe of the application built in PowerPoint. The CEO was impressed that they already had a UI where you could click buttons and navigate to the next screen, and took this to mean that they were basically done already. He wrote them a check for an amount in the millions, and off they went to work.Many months later, the offshore team handed off the code. The first time, it didn't build. The second time, what unit tests there were didn't pass. The third time, it didn't build again. By the fifth time, the offshore team handed them Java code which would build and run, and only crash unexpectedly some of the time.This code used certain… patterns. The same basic approaches to doing simple tasks were reused everywhere, because clearly this code base was implemented by copy-pasting snippets from other projects, from elsewhere in this project or from the first hit on a search result.On such pattern was how they handled passing primitive types around:
|
by Remy Porter on (#5NNEX)
If you have an object, say a Job, which can be in multiple states, you'll frequently need to execute different code, depending on the state. Enter the ever useful switch statement, and all those problems are solved.Or are they? Reva found this Java code. Enjoy your 112 line switch statement:
|
by Lyle Seaman on (#5NJ2K)
We like to think of Error'd as a safe place for pedants.
|
by Remy Porter on (#5NGYC)
Just because someone writes in C, and not some more modern language doesn't mean they're going to be an expert in how to operate on binary values.Carl W found this bit of C code with a simple goal: count the number of trailing zeroes in a 32-bit integer. At least, that's what the function name tells us. Reading the logic, I'm less certain.
|
by Remy Porter on (#5NFFY)
Repentinus submitted a pull request to a project he was working on. The Python code Repentinus submitted was this:
|
by Remy Porter on (#5NE21)
Today, let's just start with a single line of Java code, from Rich.
|
by Remy Porter on (#5NCPS)
Some languages support operator overloading. Others, like Java, do not. There are good arguments on either side for whether or not you should support the feature, but when you don't, you need an easy way to get the effects of operators without the syntactic sugar.For example, if you have a custom class, and you need a way to perform comparisons on them, you may choose to implement the Comparator interface. This allows you to add some kind of comparison to an object without actually touching the object's implementation. For example, you might do something like:
|
by Lyle Seaman on (#5N9JN)
Dating from a few months back, our opening submission for the week is only funny if you don't see it as a painful forecast of some comingsummer in the City of Lights. Keeping with the theme of trapped systems, mostly Windows, here follow more multinational kiosk misadventures."Wear sunscreen," warns Thomas, temperately. "It's unseasonably warm."
|
by Remy Porter on (#5N821)
One of the advantages of interpreted languages, like Python, is that when your vendor ships a tool that uses Python… you can see how the Python bits actually work. Or maybe seeing how the sausage is made is a disadvantage?Delana's vendor tool needs to determine the IP address of the computer in a platform independent way. The "standard" way of doing this in Python is to check the computer's hostname then feed that into a function like one of these which turns it into IP addresses.Those methods should behave more-or-less the same on both Windows and Linux, so checking the IP address should be a simple and short function. Let's see how Delana's vendor did it:
|
by Remy Porter on (#5N6K9)
Kaci had one of "those" co-workers who didn't believe in source control. As you modified code, you'd just comment out bits and pieces, maybe replace some of it. That way you could see how the code evolved without having to learn how to use git log correctly.At least, that was the rough argument. But it meant that when Kaci wanted to understand why this block of PHP code existed, she needed to ask the developer:
|
by Remy Porter on (#5N53Q)
Sometimes, readers submit code and say, "every line is wrong!" Usually, they mean that every line contains a bad choice, or represents a bad way of accomplishing the program's goal, or there's a series of compounding mistakes.David sends us a block which… well, yes, every line is wrong, because every line contradicts every other one.
|