Feed the-daily-wtf The Daily WTF

Favorite IconThe Daily WTF

Link http://thedailywtf.com/
Feed http://syndication.thedailywtf.com/TheDailyWtf
Updated 2024-11-22 08:16
Error'd: Fast Hail and Round Wind
"He's not wrong. With wind and hail like this, an isolated tornado definitely ranks third in severity," Rob K. writes.
CodeSOD: Rings False
There are times when a code block needs a lot of setup, and there are some where it mostly speaks for itself. Today’s anonymous submitter found this JavaScript in a React application, coded by one of the senior team-members.
CodeSOD: Going on an Exceptional Date
Here’s a puzzler for you: someone has written bad date handling code, but honestly, the bad date handling isn’t the real WTF. I mean, it’s bad, but it highlights something worse.Cid inherited this method, along with a few others which we’ll probably look at in the future. It’s Java, so let’s just start with the method signature.
CodeSOD: Dates Float
In a lot of legacy code, I've come across "integer dates". It's a pretty common way to store dates in a compact format: an integer in the form "YYYYMMDD", e.g., 20200616 It's relatively compact, it remains human readable (unlike a Unix epoch). It's not too difficult to play with the modulus and rounding operators to pick it back into date parts, if you need to, though mostly we'd use something like this as an ID-like value, or for sorting.Thanks to Katie E I've learned about a new format: decimal years. The integer portion is the year, and the decimal portion is how far through that year you are, e.g. 2020.4547. This is frequently used in statistical modeling to manage time-series data. Once again, it's not meant to be parsed back into an actual date, but if you're careful, you can do it.Unless you're whoever wrote this C++ code, which Katie found.
Faking the Grade
Our friend and frequent submitter Argle once taught evening classes in programming at his local community college. These classes tended to be small, around 20-30 students. Most of them were already programmers and were looking to expand their knowledge. Argle enjoyed helping them in that respect.The first night of each new semester, Argle had everyone introduce themselves and share their goals for the class. One of his most notable students was a confident, charismatic young man named Emmanuel. "Manny," as he preferred to be called, told everyone that he was a contract programmer who'd been working with a local company for over a year."I don't really need to be here," he said. "My employer thought it would be nice if I brushed up on the basics."Argle's first assignment for the class was a basic "Hello, world" program to demonstrate knowledge of the development environment. Manny handed it in with an eye-roll—then failed to turn in any more homework for the rest of the semester. He skipped lectures and showed up only for exams, each time smirking like he had the crib sheet to the universe in his back pocket. And yet he bombed every test in spectacular fashion, even managing to score below 50% on the true/false midterm. A layperson off the street could've outperformed him with random guessing.Argle made attempts to offer help during office hours, all of which Manny ignored. This being college and not grade school, there wasn't much else Argle could do. Manny was an adult who'd turned in an F performance, so that was the grade he ended up with.A few days after final grades had been submitted, Argle received a phone call from Manny. "I don't understand why you failed me," he began with full sincerity.Baffled, Argle was speechless at first. Is this a joke? he wondered. "You didn't turn in any assignments," he explained, trying to keep emotion out of his voice. "Assignments were worth two-thirds of the grade. It's in the syllabus, and I discussed it on the first day of class.""I thought my test grades would carry me," Manny replied.Argle's bafflement only grew. "Even if you'd gotten perfect scores on every test, you still would've failed the class. And you had nowhere near perfect scores on the tests."Manny broke down crying. He kept talking, almost incomprehensible through his sobs. "My employer paid for the class! They're going to see the grade! I'm not losing my job over this. I'm contesting the F!" He abruptly hung up.Argle made a quick preemptive phone call to his department head to explain the situation, and was assured that everything would be taken care of. Upon ending the call, he shook his head in astonishment. Had Manny's employer suspected that their contractor wasn't as skilled with programming as he pretended to be? Or would his F come as a total shock to them?A programmer who doesn't know how to program, he mused to himself, and management who can't tell the difference. Sounds like a match made in heaven.Argle never heard about the issue again, so he never learned Manny's fate. But once he discovered our website, he came to understand that Manny was far from the only "brillant" programmer out there, and far from the only one whose incompetence went undetected for so long. [Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!
Error'd: People also ask ...WTF?!
"Exactly which people are asking this question?" Jamie M. wrote.
The Time-Delay Footgun
A few years back, Mike worked at Initech. Initech has two major products: the Initech Creator and the Initech Analyzer. The Creator, as the name implied, let you create things. The Analyzer could take what you made with the Creator and test them.For business reasons, these were two separate products, and it was common for one customer to have many more Creator licenses than Analyzer licenses, or upgrade them each on a different cadence. But the Analyzer depended on the Creator, so someone might have two wildly different versions of both tools installed.Initech wasn’t just incrementing the version number and charging for a new seat every year. Both products were under active development, with a steady stream of new features. The Analyzer needed to be smart enough to check what version of Creator was installed, and enable/disable the appropriate set of features. Which meant the Analyzer needed to check the version string.From a user’s perspective, the version numbers were simple: a new version was released every year, numbered for the year. So the 2009 release was version 9, the 2012 was version 12, and so on. Internally, however, they needed to track finer-grained versions, patch levels, and whether the build was intended as an alpha, beta, or release version. This meant that they looked more like “12.3g31”.Mike was tasked with prepping Initech Analyzer 2013 for release. Since the company used an unusual version numbering schema, they had also written a suite of custom version parsing functions, in the form: isCreatorVersion9_0OrLater, isCreatorVersion11_0OrLater, etc. He needed to add isCreaterVersion12_0OrLater.“Hey,” Mike suggested to his boss, “I notice that all of these functions are unique, we could make a general version that uses a regex.”“No, don’t do that,” his boss said. “You know what they say, ‘I had a problem, so I used regexes, now I have two problems.’ Just copy-paste the version 11 version, and use that. It uses string slicing, which performs way better than regex anyway.”“Well, I think there are going to be some problems-”“It’s what we’ve done every year,” his boss said. “Just do it. It’s the version check, don’t put any thought into it.”“Like, I mean, really problems- the way it-”His boss cut him off and spoke very slowly. “It is just the version check. It doesn’t need to be complicated. And we know it can’t be wrong, because all the tests are green.”Mike did not just copy the version 11 check. He also didn’t use regexes, but patterned his logic off the version 11 check, with some minor corrections. But he did leave the version 11 check alone, because he wasn’t given permission to change that block of code, and all of the tests were green.So how did isCreatorVersion11_0OrLater work? Well, given a version string like 9.0g57 or 10.0a12, or 11.0b9, it would start by checking the second character. If it was a ., clearly we had a single digit version number which must be less than 11. If the second character was a 0, then it must be 10, which clearly is also less than 11, and there couldn't possibly be any numbers larger than 11 which have a "0" as their second character. Any other number must be greater than or equal 11.Mike describes this as a “time-delayed footgun”. Because it was “right” for about a decade. Unfortunately, Initech Analyzer 2020 might be having some troubles right now…Mike adds:
CodeSOD: Sort Yourself Out
Object-Relational-Mappers (ORMs) are a subject of pain, pleasure, and flamewars. On one hand, they make it trivially easy to write basic persistence logic, as long as it stays basic. But they do this by concealing the broader powers of relational databases, which means that an ORM is a leaky abstraction. Used incautiously or inappropriately, and they stop making your life easy, and make it much, much harder.That’s bad, unless you’re Tenesha’s co-worker, because you apparently want to suffer.In addition to new products, Tenesha’s team works on a legacy Ruby-on-Rails application. It’s an ecommerce tool, and thus it handles everything from inventory to order management to billing to taxes.Taxes can get tricky. Each country may have national tax rates. Individual cities may have different ones. In their database, they have a TaxesRate table which tracks the country name, the city name, the region code name, and the tax rate.You’ll note that the actual database is storing names, which is problematic when you need to handle localizations. Is it Spain or España? The ugly hack to fix this is to have a lookup file in YAML, like so:
Representative Line: The Truest Comment
Usually, when posting a representative line, it’s a line of code. Rarely, it’s been a “representative comment”.Today’s submitter supplied some code, but honestly, the code doesn’t matter- it’s just some method signatures. The comment, however, is representative. Not just representative of this code, but honestly, all code, everywhere.
Editor's Soapbox: On Systemic Debt
I recently caught up with an old co-worker from my first "enterprise" job. In 2007, I was hired to support an application which was "on its way out," as "eventually" we'd be replacing it with a new ERP. September 2019 was when it finally got retired.The application was called "Total Inventory Process" and it is my WTF origin story. Elements of that application and the organization have filtered into many of my articles on this site. Boy, did it have more than its share of WTFs."Total Inventory Process". Off the bat, you know that this is a case of an overambitious in-house team trying to make a "do everything" application that's gonna solve every problem. Its core was inventory management and invoicing, but it had its own data-driven screen rendering/templating engine (which barely worked), its own internationalization engine (for an application which never got localized), a blend of web, COM+, client-side VB6, and hooks into an Oracle backend but also a mainframe.TIP was also a lesson in the power of technical debt, how much it really costs, and why technical solutions are almost never enough to address technical debt.TIP was used to track the consumption of inventory at several customers' factories to figure out how to invoice them. We sold them the paint that goes on their widgets, but it wasn't as simple as "You used this much paint, we bill you this much." We handled the inventory of everything in their paint line, from the paint to the toilet paper in the bathrooms. The customer didn't want to pay for consumption, they wanted to pay for widgets. The application needed to be able to say, "If the customer makes 300 widgets, that's $10 worth of toilet paper."The application handled millions of dollars of invoices each year, for dozens of customer facilities. When I was hired, I was the second developer hired to work full time on supporting TIP. I wasn't hired to fix bugs. I wasn't hired to add new features. I was hired because it took two developers, working 40 hours a week, just to keep the application from falling over in production.My key job responsibility was to log into the production database and manually tweak records, because the application was so bug-ridden, so difficult to use, and so locked down that users couldn't correct their own mistakes. With whatever time I had left, I'd respond to user requests for new functionality or bug-fixes.It's usually hard to quantify exactly what technical debt costs. We talk about it a lot, but it very often takes the form of, "I know it when I see it," or "technical debt is other people's code." Here, we have a very concrete number: technical debt was two full-time salaries to just maintain basic operations.My first development task was to add a text-box to one screen. Because other developers had tried to do this in the past, the estimate I was given was two weeks of developer time. 80 hours of effort for a new text box.Once, the users wanted to be able to sort a screen in descending order. The application had a complex sorting/paging system designed to prevent fetching more than one page of data at a time for performance reasons. While it did that, it had no ability to sort in descending order, and adding that functionality would have entailed a full rewrite. My "fix" was to disable paging and sorting entirely on the backend, then re-implement in on the client-side in JavaScript for that screen. The users loved it, because suddenly one screen in the application was actually fast.Oh, and as it was, "sorting" on the backend was literally putting the order-by clause in the URL and then SQL injecting it.There were side effects to this quantity of technical debt. Since we were manually changing data in production, we were working closely with a handful of stakeholder users. Three, in specific, who were the "triumvirate" of TIP. Those three people were the direct point of contact with the developers. They were the direct point of contact to management. They set priorities. They entered bug reports. They made data change requests. They ruled the system.They had a lot of power over this system, and this was a system handling millions of dollars. I think they liked that power. To this day, one of them holds that the "concept" of TIP was "unbeatable", and its replacement system is "cheap" and "crap". Now, from a technical perspective, you can't really get crappier than TIP, but from the perspective of a super-user, I can understand how great TIP felt.I was a young developer, and didn't really like this working environment. Oh, I liked the triumvirate just fine, they were lovely people to work with, but I didn't like spending my days as nothing more than an extension of them. They'd send me emails containing UPDATE statements, and just ask that I execute them in production. There's not a lot of job satisfaction in being nothing more than "the person with permission to change data."Frustrated, I immediately starting looking for ways to pay down that technical debt. There was only so much I could do, for a number of reasons. The obvious one was the software. If "adding a textbox" could reasonably take two weeks, "restructuring data access so that you can page data sorted in descending order" felt impossible. Even "easy" changes could unleash chaos as they triggered some edge case no one knew about.Honestly, though, the technical obstacles were the small ones. The big challenges were the cultural and political ones.First, the company knew that much of the code running in production was bad. So they created policies which erected checkpoints to confirm code quality, making it harder to deploy new code. Much harder, and much longer: you couldn't release to production until someone with authority signed off on it, and that might take days. Instead of resulting in better code, it instead meant the old, bad code stayed bad, and new, bad code got rushed through the process. "We have a hard go-live date, we'll improve the code after that." Or people found other workarounds: your web code had to go through those checkpoints, but stored procedures didn't, so if you had the authority to modify things in production, like I did, you could change stored procedures to your heart's content.Second, the organization as a whole was risk-averse. The application was handling millions of dollars of invoices, and while it required a lot of manual babysitting, by the time the invoices went out, they were accurate. The company got paid. No one wanted to make sweeping changes which could impact that.Third, the business rules were complicated. "How many rolls of toilet paper do you bill per widget?" is a hard question to answer. It's fair to say that no one fully understood the system. On the business side, the triumvirate probably had the best handle on it, but even they could be blindsided by its behavior. It was a complex system that needed to stay functioning, because it was business critical, but no one knows exactly what all of those functions are.Fourth, the organization viewed "support" and "enhancement" the way other companies might view "operational" and "capital" budgets. They were different pools of money, and you weren't supposed to use the support money to pay for new features, nor could enhancement money be used to fix bugs.Most frustrating was that I would sometimes get push-back from the triumvirate. Oh, they loved it when I could give them a button to self-service some feature which needed to use manual intervention, so long as the interface was just cumbersome enough that only they could use it. They hated it when a workflow got so streamlined that any user could do it. Worse, for them, was that as the technical debt got paid down, we started transitioning more and more of the "just change production data" to low-level contractors. Now the triumvirate no longer had a developer capable of changing code at their beck and call. They had to surrender power.Fortunately, management was sensitive to the support costs around TIP. Once we started to build a track-record of reduced costs, management started to remove some of the obstacles. It was a lot of politics. I suspect some management were wary of how much power the triumvirate had, and were happy when that could get reduced. After a few years of work on TIP, I mostly rolled off of it onto other projects. Usually, I'd just pop in for month-end billing support, or being the expert who understood some of the bizarre technical intricacies. Obviously, the application continued working just fine for years without me, and I can't say that I miss it.TIP accrued technical debt far more quickly than most systems would. Some of that comes from ambition: it tried to be everything, including reinventing functions which had nothing to do with its core business. This led to a tortured development process, complete with death marches, team restructurings, "throw developers at this until it gets back on track," and several ultimatums like "If we don't get something in production by the end of the month, everyone is fired." It was born in severe debt, within an organization which didn't have good mechanisms to manage that debt. And the main obstacles to paying down that debt weren't technical: they were social and political.I was lucky. I was given the freedom to tackle that debt (or, if we're being fully honest, I also took some freedom under the "it's easier to seek forgiveness than to ask permission" principle). In a lot of systems, the technical debt accrues until the costs of servicing the debt are untenable. You end up paying so much in "interest" that you stop being able to actually do anything. This is a failure mode for a lot of projects, and that's usually when a "ground up" rewrite happens. Rewrites have a mixed record, though: TIP itself was actually a rewrite of an older system and promised to "do it right" this time.Technical debt has been on my mind because I've been thinking a lot lately about broader, systemic debt. Any systems humans build—software systems, mechanical systems, or even social systems—are going to accrue debt. Decisions made in the history of the system are going to create problems in the future, whether those decisions were wrong from the get-go, or had unforeseen consequences, or just the world changed and they're no longer workable.The United States, right now, is experiencing a swell of protests unlike anything I've seen in my lifetime. I think it's fair to say that these protests are rooted in historical inequities and injustices which constitute a form of social debt. Our social systems, especially around the operation of police, but broadly in the realm of race, are loaded with debt from the past.I see similarities in the obstacles to paying down that debt. Attempts to make changes by policy end up creating roadblocks to change, or simply fail to accomplish their goals. Resistance to change because change entails risk, and managing or mitigating those risks feels more important than actually fixing the problems. The systems we're talking about are complicated, and it's difficult to even build consensus on what better versions look like, because it's difficult to even understand what they currently are. And finally, there are groups that have power, and in paying down the social debt, they would have to give up some of that power.That's a big, hard-to-grapple-with quantity of debt. It's connected to a set of interlocking systems which are difficult to pick apart. And it's frighteningly important to get right.All systems accrue systemic debt. Software systems accrue debt. Social systems accrue debt. Even your personal mental systems, your psychological health, accrue debt. Without action, the debt will grow, the interest on that debt grows, and more energy ends up servicing that debt. One of the ways in which systems fail is when the accumulated debt gets too high. Bankruptcy occurs. Of all of these kinds of systems, the software debt tends to be the trivial one. Software products become unsupportable and get replaced. Psychological debt can lead towards things like depression or other mental health problems. Social debt can lead to unrest or perpetuations of injustice.Systemic debt may be a technical problem at its root, but its solution is always going to require politics. TIP couldn't be improved without overcoming political challenges. US social debt can't be resolved without significant political changes.What I hope people take away from this story is an awareness of systemic debt, and an understanding of some of the long-term costs of that debt. I encourage you to look around you and at the systems you interact with. What sources of debt are there? What is that debt costing the system and the people who depend on it? What are the obstacles to paying down that debt? What are the challenges of making the systems we use better?Systemic debt doesn't go away by itself, and left unmanaged, it will only grow. If you don't pay attention to it, broken systems end up staying in production for way too long. TIP was used for nearly 18 years. Don't use broken things for that long, please. [Advertisement] ProGet can centralize your organization's software applications and components to provide uniform access to developers and servers. Check it out!
Error'd: Just a Big Mixup
Daniel M. writes, "How'd they make this mistake? Simple. You add the prices into the bowl and turn the mixer on."
CodeSOD: Scheduling your Terns
Mike has a co-worker who’s better at Code Golf than I am. They needed to generate a table with 24 column headings, one for each hour of the day, formatted in HAM- the hour and AM/PM. As someone bad at code golf, my first instinct is honestly to use two for loops, but in practice I’d probably do a 24 iteration loop with a branch to decide if it’s AM/PM and handle it appropriately, as well as a branch to handle the fact that hour 0 should be printed as 12.Which, technically, more or less what Mike’s co-worker did, but they did in in golf style, using PHP.
CodeSOD: Synchronize Your Clocks
Back when it was new, one of the “great features” of Java was that it made working with threads “easy”. Developers learning the language were encouraged to get a grip right on threads right away, because that was the new thing which would make their programs so much better.Well, concurrency is hard. Or, to put it another way, “I had a problem, so I decided to use threads. prhave twI Now o oblems.”Another thing that’s hard in Java is working with dates and times.Larisa inherited some code which wanted to be able to check the current system time in a threadsafe fashion. They weren’t doing anything fancy- no timezones, no formatting, just getting the Unix Timestamp off the clock. If you’re thinking to yourself, “It’s just a read operation and there’s no need to bring threads into this at all,” you obviously didn’t write today’s code block.The right way to do this in Java 8+, would be to use the built-in java.time objects, but in older versions of Java you might need to do something like this:
CodeSOD: Try a Different Version
Back when I was still working for a large enterprise company, I did a lot of code reviews. This particular organization didn’t have much interest in code quality, so a lot of the code I was reviewing was just… bad. Often, I wouldn’t even need to read the code to see that it was bad.In the olden times, inconsistent or unclear indentation was a great sign that the code would be bad. As IDEs started automating indentation, you lost that specific signal, but gained a new one. You can just tell code is bad when it’s shaped like this:
CodeSOD: Don't be so Negative Online
It's fair to say that regardless of their many advantages, "systems languages", like C, are much harder to use than their more abstract cousins.Vendors know this, which is why they often find a way to integrate across language boundaries. You might write critical functions in C or C++, then invoke them in Python or from Swift or… Visual Basic 6.And crossing those language boundaries can pose other challenges. For example, Python has a built-in boolean type. C, for quite a long time didn't. Which means a lot of C code has blocks like this:
Error'd: A Pattern of Errors
"Who would have thought that a newspaper hired an ex-TV technician to test their new CMS with an actual test pattern!" wrote Yves.
CodeSOD: This is Your Last Birthday
I have a philosophy on birthdays. The significant ones aren’t the numbers we usually choose- 18, 21, 40, whatever- it’s the ones where you need an extra bit. 2, 4, 8, and so on. By that standard, my next birthday landmark isn’t until 2044, and I’m a patient sort.Christian inherited some legacy C# code which deals in birthdays. Specifically, it needs to be able to determine when your last birthday was. Now, you have to be a bit smarter than simply “lop off the year and insert this year,” since that could be a future birthday, but not that much smarter.The basic algorithm most of us would choose, though, might start there. If their birthday is, say, 12/31/1969, then we could ask, is 12/31/2020 in the future? It is. Then their last birthday was on 12/31/2019. Whereas, for someone born on 1/1/1970, we know that 1/1/2020 is in the past, so their last birthday was 1/1/2020.Christian’s predecessor didn’t want to do that. Instead, they found this… “elegant” approach:
CodeSOD: Is We Equal?
Testing for equality is hard. Equal references are certainly equal, but are equal values? What does it mean for two objects to “equal” each other? It’s especially hard in a language like JavaScript, which is “friendly” about type conversions.In JavaScript land, you’re likely to favor a tool like “lodash”, which provides utility functions like isEqual.Mohsin was poking around an old corner of their codebase, which hadn’t been modified in some time. Waiting there was this “helpful” function.
A Vintage Printer
Remember Robert, the student who ruined his class curve back in the 1960s? Well, proving the old adage that the guy who graduates last from medical school is still a doctor, he managed to find another part-time job at a small hospital, earning just enough to pay his continued tuition.Industry standard in those days was the IBM System/360 series, but it was out of the price range of this hospital. Instead, they had an IBM 1130, which was designed to be used in laboratories and small scientific research facilities. It used FORTRAN, which was pretty inappropriate for business use, but a set of subroutines offered by IBM contained routines for dealing with currency values and formatting. The hospital captured charges on punch cards and those were used as input to a billing program.The printer was a monstrous beast, spinning a drum of characters and firing hammers to print characters as they went by. In order to print in specific boxes on the billing forms, it was necessary to advance the paper to a specific point on the page. This was done using a loop of paper tape that had 12 channels in its width. A hole was punched at the line in the tape where the printer needed to stop. Wire brushes above the tape would hit the hole, making contact with the metal drum inside the loop and stopping the paper feed.There was one box in the billing form that was used infrequently, only every few days. When the program issued the code to skip to that channel, paper would begin spewing for a few seconds, and then the printer would shut down with a fault. This required stopping, removing the paper, typing the necessary data into the partially-printed bill, and then restarting the job from the point of failure.IBM Field Engineering was called, but was unable to find a reason for the problem. Their considered opinion was that it was a software fault. After dealing with the problem on a fairly regular basis, things escalated. The IBM Systems Engineer assigned to the site was brought in.Robert's boss, the author of the billing software, had relied on an IDEAL subroutine package provided by IBM—technically unsupported, but written by IBM employees, so generally one would assume it was safe to use. The Systems Engineer spent a while looking over that package, but eventually declared it innocent and moved on. He checked over the code Robert's boss had written, but ultimately that, too, failed to provide any answers."Then it must be the machine," Robert's boss stated.This was the wrong thing to say. "It couldn't be the machine!" The Engineer, a prideful young woman, bristled at the insinuation. "These machines are checked. Everything's checked before it leaves the factory!"Tempers flared, voices on the edge of shouting. Robert ducked back into the room with the computer, followed rapidly by the Field Engineer who had come along earlier in the day to do his own checks. Trying to pretend they couldn't hear the argument, the pair began another once-over on the machine, looking for any sign of mechanical fault."Hey, a question," said Robert, holding the thick cable that connected the printer to the computer. "Could it be a problem with the cable?"The Field Engineer unplugged the cable and examined it. "The pin for that channel doesn't look seated," he admitted sheepishly. "Let's replace it and see what happens."That day Robert learned two valuable lessons in debugging. Number one: when in doubt, go over each piece of the machine, no matter how unlikely. Number two: never tell an IBM Engineer that the problem is on their end. [Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!
CodeSOD: Classic WTF: A Char'd Enum
Error'd: Rest in &;$(%{>]$73!47;£*#’v\
"Should you find yourself at a loss for words at the loss of a loved one, there are other 'words' you can try," Steve M. writes.
CodeSOD: Checking Your Options
If nulls are a “billion dollar mistake”, then optional/nullable values are the $50 of material from the hardware store that you use to cover up that mistake. It hasn’t really fixed anything, but if you’re handy, you can avoid worrying too much about null references.D. Dam Wichers found some “interesting” Java code that leverages optionals, and combines them with the other newish Java feature that everyone loves to misuse: streams.First, let’s take a look at the “right” way to do this though. The code needs to take a list of active sessions, filter out any older than a certain threshold, and then summarize them together into a single composite session object. This is a pretty standard filter/reduce scenario, and in Java, you might write it something like this:
CodeSOD: A Maskerade
Josh was writing some code to interact with an image sensor. “Fortunately” for Josh, a co-worker had already written a nice large pile of utility methods in C to make this “easy”.So, when Josh wanted to know if the sensor was oriented in landscape or portrait (or horizontal/vertical), there was a handy method to retrieve that information:
The Dangerous Comment
It is my opinion that every developer should dabble in making their own scripting language at least once. Not to actually use, mind you, but to simply to learn how languages work. If you do find yourself building a system that needs to be extendable via scripts, don’t use your own language, but use a well understood and well-proven embeddable scripting language.Which is why Neil spends a lot of time looking at Tcl. Tcl is far from a dead language, and its bundled in pretty much every Linux or Unix, including ones for embedded platforms, meaning it runs anywhere. It’s also a simple language, with its syntax described by a relatively simple collection of rules.Neil’s company deployed embedded network devices from a vendor. Those embedded network devices were one of the places that Tcl runs, and the company which shipped the devices decided that configuration and provisioning of the devices would be done via Tcl.It was nobody’s favorite state of affairs, but it was more-or-less fine. The challenges were less about writing Tcl and more about learning the domain-specific conventions for configuring these devices. The real frustration was that most of the time, when something went wrong, especially in this vendor-specific dialect, the error was simply: “Unknown command.”As provisioning needs got more and more complicated, scripts calling out to other scripts became a more and more common convention, which made the “Unknown command” errors even more frustrating to track down.It was while digging into one of those that Neil discovered a special intersection of unusual behaviors, in a section of code which may have looked something like:
CodeSOD: Extra Strict
One of the advantages of a strongly typed language is that many kinds of errors can be caught at compile time. Without even running the code, you know you've made a mistake. This adds a layer of formality to your programs, which has the disadvantage of making it harder for a novice programmer to get started.At least, that's my understanding of why every language that's designed to be "easy to use" defaults to being loosely typed. The result is that it's easy to get started, but then you inevitably end up asking yourself wat?Visual Basic was one of those languages. It wanted to avoid spitting out errors at compile time, because that made it "easy" to get started. This meant, for example, that in old versions of Visual Basic, you didn't need to declare your variables- they were declared on use, a feature that persists into languages like Python today. Also, in older versions, you didn't need to declare variables as having a type, they could just hold anything. And even if you declared a type, the compiler would "do its best" to stuff one type into another, much like JavaScript does today.Microsoft recognized that this would be a problem if a large team was working on a Visual Basic project. And large teams and large Visual Basic projects are a thing that sadly happened. So they added features to the language which let you control how strict it would be. Adding Option Explicit to a file would mean that variables needed to be declared before use. Option Strict would enforce strict type checking, and preventing surprising implicit casts.One of the big changes in VB.Net was the defaults for those changed- Option Explicit defaulted to being on, and you needed to specify Option Explicit Off to get the old behavior. Option Strict remained off by default, though, so many teams enabled it. In .NET, it was even more important, since while VB.Net might let you play loose with types at compile time, the compiled MSIL output didn't.Which brings us to Russell F's code. While the team's coding standards do recommend that Option Strict be enabled, one developer hasn't quite adapted to that reality. Which is why pretty much any code that interacts with form fields looks like this:
Error'd: Destination Undefined
"It's good that I'm getting off at LTH, otherwise God knows what'd have happened to me," Elliot B. writes.
CodeSOD: I Fixtured Your Test
When I was still doing consulting, I had a client that wanted to create One App To Rule Them All: all of their business functions (and they had many) available in one single Angular application. They hoped each business unit would have their own module, but the whole thing could be tied together into one coherent experience by setting global stylesheets.I am a professional, so I muted myself before I started laughing at them. I did give them some guidance, but also tried to set expectations. Ignore the technical challenges. The political challenges of getting every software team in the organization, the contracting teams they would bring in, the management teams that needed direction, all headed in the same direction were likely insurmountable.Brian isn’t in the same situation, but Brian has been receiving code from a team of contractors from Initech. The Initech contractors have been a problem from the very start of the project. Specifically, they are contractors, and very expensive ones. They know that they are very expensive, and thus have concluded that they must also be very smart. Smarter than Brian and his peers.So, when Brian does a code review and finds their code doesn’t even approach his company’s basic standards for code quality, they ignore him. When he points out that they’ve created serious performance problems by refusing to follow his organization’s best practices, they ignore him and bill a few extra hours that week. When the project timeline slips, and he starts asking about their methodology, they refuse to tell him a single thing about how they work beyond, “We’re Agile.”To the shock of the contractors and the management paying the bills, sprint demos started to fail. QA dashboards went red. Implementation of key features got pushed back farther and farther. In response, management decided to give Brian more supervisory responsibility over the contractors, starting with a thorough code review.He’s been reviewing the code in detail, and has this to say:
CodeSOD: A Short Trip on the BobC
More than twenty years ago, “BobC” wrote some code. This code was, at the time, relatively modern C++ code. One specific class controls a display, attached to a “Thingamobob” (technical factory term), and reporting on the state of a number of “Doohickeys”, which grows over time.The code hasn’t been edited since BobC’s last change, but it had one little, tiny, insignificant problem. It would have seeming random crashes. They were rare, which was good, but “crashing software attached to factory equipment” isn’t good for anyone.Eventually, the number of crash reports was enough that the company decided to take a look at it, but no one could replicate the bug. Johana was asked to debug the code, and I’ve presented it as she supplied it for us:
Representative Line: Don't Negate Me
There are certain problem domains where we care more about the results and the output than the code itself. Gaming is the perfect example: game developers write "bad" code because clarity, readability, maintainability are often subordinate to schedules and the needs of a fun game. The same is true for scientific research: that incomprehensible blob of Fortran was somebody's PhD thesis, and it proved fundamental facts about the universe, so maybe don't judge it on how well written it is.Sometimes, finance falls into similar place. Often, the software being developer has to implement obtuse business rules that accreted over decades of operation; sometimes it's trying to be a predictive model; sometimes a pointy-haired-boss got upset about how a dashboard looked and asked for the numbers to get fudged.But that doesn't mean that we can't find new ways to write bad code in any of these domains. René works in finance, and found this unique JavaScript solution to converting a number to a negative value:
CodeSOD: Selected Sort
Before Evalia took a job at Initech, her predecessor, "JR" had to get fired first. That wasn't too much of a challenge, because JR claimed he was the "God of JavaScript". That was how he signed each of the tickets he handled in the ticket system.JR was not, in fact, a god. Since then, Evalia has been trying to resuscitate the projects he had been working on. That's how she found this code.
Error'd: Errors as Substitution for Success
"Why would I be a great fit? Well, [Recruiter], I can [Skill], [Talent], and, most of all, I am certified in [qualification]." David G. wrote.
Representative Line: Separate Replacements
There's bad date handling code. There's bad date formatting code. There's bad date handling code that abuses date formatting to stringify dates. There are cases where the developer clearly doesn't know the built-in date methods, and cases where they did, but clearly just didn't want to use them.There's plenty of apocalypticly bad date handling options, but honestly, that gets a little boring after awhile. My personal favorite will always be the near misses. Code that almost, but not quite, "gets it".Karl's co-worker provided a little nugget of exactly that kind of gold.
CodeSOD: Dating Automation
Good idea: having QA developers who can build tooling to automate tests. Testing is tedious, testing needs to be executed repeatedly, and we're not just talking simple unit tests, but in an ideal world key functionality gets benchmarked against acceptance tests. API endpoints get routinely checked.There's costs and benefits to this though. Each piece of automation is another piece of code that needs to be maintained. It needs to be modified as requirements change. It can have bugs.And, like any block of code, it can have WTFs.Nanette got a ticket from QA, which complained that one of the web API endpoints wasn't returning data. "Please confirm why this API isn't returning data."It didn't take long before Nanette suspected the problem wasn't in the API, but may be in how QA was figuring out its date ranges:
CodeSOD: Reasonable Lint
While testing their application, Nicholas found some broken error messages. Specifically, they were the embarassing “printing out JavaScript values” types of errors, so obviously something was broken on the server side.“Oh, that can’t be,” said his senior developer. “We have a module that turns all of the errors into friendly error messages. We use it everywhere, so that can’t be the problem.”Nicholas dug in, and found this NodeJS block, written by that senior developer.
CodeSOD: The Sound of GOTO
Let's say you have an audio file, or at least, something you suspect is an audio file. You want to parse through the file, checking the headers and importing the data. If the file is invalid, though, you want to raise an error. Let's further say that you're using a language like C++, which has structured exception handling.Now, pretend you don't know how to actually use structured exception handling. How do you handle errors?Adam's co-worker has a solution.
Error'd: Call Me Maybe (Not)
Jura K. wrote, "Cigna is trying to answer demand for telehealth support, but apparently they are a little short on supply."
CodeSOD: A Quick Escape
I am old. I’m so old that, when I entered the industry, we didn’t have specializations like “frontend” and “backend” developers. You just had developers, and everybody just sort muddled about. As web browsers have migrated from “document display tool” to “enh, basically an operating system,” in terms of complexity, these two branches of development have gotten increasingly siloed.Which creates problems, like the one Carlena found. You see, the front-end folks didn’t like the way things like quotes were displaying. A quote or a single quote should be represented as a character entity- &#39, for example.Now, our frontend developers could have sanitized the strings for display on the client side, but making sure the frontend got good data was a backend problem, to their mind. But the backend developer was out of the office on vacation, so what were our struggling frontend folks to do?
Rushin' Translation
Cid works for a German company. From day one, management knew that they wanted their application to be multi-lingual, if nothing else because they knew they needed to offer it in English. So from the ground up, the codebase was designed to make localization easy; resource files contained all the strings, the language specific ones could be loaded dynamically, and even UI widgets could flex around based on locale needs.In the interests of doing it right, when it came time to make the English version, they even went out and contracted a translation company. A team of professional translators went through the strings, checked through the documentation and the requirements, even talked to stakeholders to ensure accurate translations. The English version shipped, and everyone- company and customers included were happy with the product.Cid’s employer got a lot of good press- their product was popular in its narrow domain. Popular enough that a Russian company called Инитеч came around. They wanted to use the product, but they wanted a Russian localization.“No problem,” said the sales beast. “We can make that happen!”Management was less enthused. When localizing for English, they knew they had a big market, and they knew that it was worth doing it right, but even then, it was expensive. Looking at the bottom line, it just didn’t make sense to put that kind of effort into the project for just one customer.The sales beast wasn’t about to let this sale slip through their fingers, though. And Инитеч really wanted to use their product. And hey, Инитеч had a few employees who had taken a semester of English in school at some point. They could do the translation! They weren’t even looking to score a deal on support, they’d buy the software and do the translation themselves.“Free” sounded good, so management gave their blessing. Since the customer was doing all the work, no one put too much thought into timelines, or planning, or quality control. Which meant that timelines slipped, there was no plan for completing the translation, and the quality control didn’t happen until Cid had the bright idea of realizing that co-worker Marya was natively Russian and asked her to take a look at the translations.“Oh, these are great,” Marya said, “if the translator doesn’t speak either German or Russian.” The translations were roughly equivalent to taking the German original, slapping it through Google Translate to get to English, then eventually migrating to Russian by way of Hindi and Portuguese.The problems with the translation were escalated up to management, and a bunch of meetings happened to debate what to do. On one hand, these were the translations the customer made, and thus they should be happy with it. On the other, they were terrible, and at the end of the day, Cid’s employer needed to be able to stand behind its product.At this point, Инитеч was getting antsy. They’d already put a lot of work into doing the translations, and had been trying to communicate the software changes to their users for months. They didn’t have anything at all to show for their efforts.Someone in the C-level offices made the call. They’d hire a professional translator, but they’d aggressively manage the costs. They laid out a plan. They set a timeline. They established acceptance criteria.They set their timeline, however, without talking to the translation company. Essentially, they were hoping to defeat the “triangle”: they wanted to have the translation be good, be cheap, and be done fast. Reality stepped in: either they needed to pay more to bring on more translators, or they needed to let timelines slip farther.What started as a quick sale with only minimal upfront investment stretched out into a year of effort. With everyone rushing but making no progress, mistakes started cropping up. One whole module’s worth of text was forgotten in the scope document agreed to by the translation company. Someone grabbed an old version of the resource file when publishing a test build, which created a minor panic when everything was wrong. Relations with Инитеч started to break down, and the whole process went on long enough that the Инитеч employee which started the purchase changed jobs, and another contact came in with no idea of what was in flight.Which is why, when the sales beast finally was able to tell Инитеч that they had a successful Russian localization, the contact at Инитеч said, “That… is nice? Is this a sales call? Are you trying to sell us this? We just purchased a similar product from your competitor six months ago.” [Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!
CodeSOD: The Evil CMS
Content Management Systems always end up suffering, at least a little, from the Inner Platform Effect. There’s the additional problem that, unlike say, a big ol’ enterprise HR system or similar, CMSes are useful for just about everyone. It’s a quick and easy way to put together a site which anyone can maintain. But it never has enough features for your content. So you always install plugins- plugins of wildly varying quality and compatibility.Lucio Crusca was doing a security audit of a Joomla site, found this block inside an installed plugin:
CodeSOD: A Tern Off
Jim J's co-worker showed him this little snippet in the codebase.
Error'd: Burrito Font
"I've always ordered my burritos in Times New Roman. I'll have to make sure to try the Helvetica option next time I go in," Winston M. writes.
CodeSOD: WTFYou, Pay Me
Julien’s employer has switched their payroll operations to a hosted solution. The hosted solution has some… interesting features. The fact that it has a “share” button, implying you can share your paystub infromation with other people is unusual (but good: keeping salaries confidential only helps management underpay their employees). More problematic is that this feature emails it, and instead of putting in an email address manually, you instead pick off a drop-down list- which contains the email of every user of the hosted system.Seeing this, Julien had to take a peek at the code, just to see what other horrors might lurk in there.Let’s open with some ugly regexes:
CodeSOD: Bad Code and Taxes
Here in the US, “tax season” is extended into the summer. No one likes dealing with taxes, obviously, but we agree that the social benefits outweigh the costs.I can’t speak to how folks feel in Italy. But Riccardo B was perusing the Italian Revenue Service’s (INPS) website, and was having a bad time of it. This website was recently “modernized”, which Riccardo tells us cost €300M (I wasn’t able to track down much on this, and since I don’t speak Italian, I’ll take Riccardo’s word on it), so “having a bad time” doesn’t seem like it should be part of the process.Like most of us, when he started having problems, Riccardo pulled up the inspector and started debugging. Which is how he spotted this €300M treat:
Representative Line: All the Small Things
Kerry (previously) has a long held belief: people that can’t get the little things right have no hope of getting the big things right, and not just when it comes to software.Personally, I don’t think that’s truly universal, but it’s certainly a good guideline. If nothing else, seeing certain simple mistakes gives you a hint of worse things to come. Like this interface definition:
Tales from the Interview: A Sterling Interview
Marissa's not-for-profit organization sought a college graduate with the ability to code and create basic software solutions. Given their organization's financial limitations, they couldn't afford to pay employees as well as many other places could, thus they'd been struggling for over a year to find a qualified entry-level candidate. Finally, a fresh graduate came along who made a strong impression during his interview. Greg was personable and possessed the required fundamentals. There was potential for him to learn more on the job.Once the interview had ended, while Marissa escorted Greg out of the building, he told her, "Hey, I really didn't do very well today."Marissa had formed the opposite impression, but didn't interrupt."If you really want to see what I'm capable of," Greg continued, "check out my GitHub. That's where you'll see what my code is like."Marissa was more than happy to do that. She and her whole software team accessed his GitHub to examine their potential coworker's code, assuming they'd be impressed with what they found.Most of the projects were nothing special. The pièce de résistance, however, was a comprehensive open-source tool called iStarling. This particular repository had quite a bit more content to sift through than any of the others.Something struck Marissa as fishy. Acting on instinct, she did some googling and found a similar open-source tool called iWren, made by a completely different person. It wasn't merely similar—a comparison of files showed that Greg had copied the repository wholesale into his own GitHub only a few days earlier, then had done a mass find/replace of the word "Wren" to "Starling."This bird-brained attempt at plagiarism left Marissa scratching her head. If Greg had never made that parting comment to her, he probably would've been hired. Greg had done the company a solid favor by warning them about what Greg was capable of. The search for a decent employee continued. [Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!
Error'd: Normal 0 False False Errord False EN-US
Andrew G. writes, "In these difficult times, I'm glad NBC News is having a normal O...and...other...stuff."
CodeSOD: A Leap to SQL
When I was a baby programmer, I was taught that part of the power of SQL was that we had a generic, abstract language which meant we could easily change database engines out under our code without having to think about it. In short, I was taught a horrible pack of lies.For all that SQL has a standard, every database vendor has non-standard features, especially around various built-in functions. The end result is that, if you adopt SQL Server, you’re going to be on SQL Server for the life of the application. If you adopt Oracle, you will suffer that choice for the remainder of your existence on this plane and perhaps the next.What this means is that it behooves you to learn the standard functions of your chosen RDBMS. For example, in T-SQL, SQL Server’s dialect of SQL, one of the built-in functions is EOMONTH. Given a date, it tells you the last day of the month, useful for a lot of business processes.You could use that, or you could do what Darrin’s co-worker did:
CodeSOD: Highly Paid Entities
Years ago, Samuel’s company brought in some Highly Paid Consultants. The HPCs brought with them a binder full of best practices, a dedicated Agile coach, and a slick project plan that promised to accomplish everything the company needed in half the time budgeted.One of their “best practices” was the advice that “ORMs are considered harmful,” and while the existing codebase already made liberal use of .NET’s Entity Framework, their new code would be “optimized”.Those optimizations must have thrown off the project timeline- they burned through their “aggressive” project plan’s budget, then the original time-and-cost estimates, and then lingered for months trying to finish their tasks. Eventually, they moved on to the next contract, and Samuel was handed their code and told to fix the bugs and performance issues.This was HR software, so among other things, it would track employees’ “career plans”. One example query the software needed to answer was to find the one plan that was the greatest number of “challenge units” below a certain threshold.The “harmful” Entity Framework/LINQ way of answering this question would be code akin to this:
Better Off Ted
When working on a programming team, you need to make sure everyone on the team is aware of the changes you make. This is to ensure that everyone knows what task they're doing, what feature the rest of the team might not have to worry about, or any potential conflicts - among other reasons.Once those changes are made, you want them reviewed. Perhaps one other developer does it, perhaps a group, or perhaps the whole team. Once approved, the changes get applied to the live application.Adam's team has their process and it's not too different from most other software companies. Team-member Ted, however, decided that he can make changes over and over again, without telling anyone.There were three main reasons Ted wasn't reprimanded in the beginning - the first is Ted is a talented programmer, and on a team with only a handful of programmers, that's valuable. The second reason and probably more important is Ted was programming for this company since the beginning; meaning Ted knows the inside and outside of the app. And finally Ted was the only remote employee – meaning it's harder to be direct when Ted isn't even in the building.Ted thought he was doing the company a favor by improving the software to meet his needs. In practice, it meant the entire development team would have to fix, correct, or flat out remove everything Ted did. But since Ted didn't tell anyone, didn't correlate changes with any tickets, or even include clear commit comments, it was often difficult to know what exactly were his "just because" changes, and which were "real" features.During their virtual standups, Ted described himself as "a teacher," showing the younger developers the way, and preparing them for their careers. He was like a teacher, but instead of following the approved curriculum, he taught what he felt best, standards be damned. He might have the best intentions, but Ted wasn't preparing them for anything but frustration.With Ted being the only remote employee, this meant it was easy for Adam, the team-lead, to meet without Ted, and discuss what to do with Ted's constant changes. Ted couldn't simply be fired- the office politics didn't permit it. But Adam could cut his hours, and put him on tasks that didn't matter if Ted tampered with the requirements and did his own thing.Even though Ted was warned a number of times, in terms ranging from "gentle" to "this is serious, Ted", he still didn't stop making his own changes. He still let his work interfere with other developers.The reprimands got to the point where even Ted realized that his job was jeopardy. Still, he insisted on doing things his own way. Adam and the team tried to talk to him about it, tried to offer suggestions, but Ted was too stubborn to take his team's advice.Adam and the team worked on an e-commerce portal, and Ted was performing these changes on the live site; bypassing all protocol. This means that customers could actually view the changes that Ted made, in real time.Adam tried giving Ted less work, so the team wouldn't have to worry about his meddling behind the scenes as much, but Ted couldn't be stopped. The breaking point was when Ted made a change, directly merged it into master, and then published it to the live site. The change ruined mobile formatting for the features the other programmers were working on, which was annoying. But it also broke the customer's ability to purchase from the site- customers literally couldn't make purchases because of Ted's "improvements".The team had to scramble to revert to the previous build, and then unpick Ted's many commits from the history to fully revert that feature. Adam had to let Ted go – everyone on a team needs to work together. [Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!
Representative Line: The Standard StringBuilder
At a previous job, I became "The Code Review Guy". It was a big company, with a lot of bureaucracy. They were transitioning from VB6 to VB.NET and didn't trust developers to adapt to this new world, so they positioned code reviews as a "gateway" and the reviewers were guards, tasked with ensuring that any code going past met the standards.That was already a pretty bad, and pretty hostile approach. Then some code would get submitted which didn't just violate the standards, but was barely comprehensible nonsense which followed no coherent convention and couldn't be tested let alone debugged. But it was mission critical and had a scheduled release date already, so the code review process had to let it pass. "Just make some notes, and they'll fix it in a future release," was the attitude. You can imagine how much of that code got fixed.In any case, one of our standards was that developers should use a StringBuilder object, not string concatenation. Concatenation produces many, many intermediate strings, which can cause performance and garbage collection issues, while a StringBuilder avoids that.This standard was commonly violated.Which brings us to this representative line of C#, which Adeline found in a customer's code-base. I can assume that they had a similar standard: use a StringBuilder. Whoever wrote this followed those instructions to the letter:
...20212223242526272829...