The Daily WTF
Error'd: Anonymice
Three blind anonymice are unbothered by the gathering dark as we approach the winter solstice. Those of you fortunate enough to be approaching the summer solstice are no doubt gloating. Feel free, we don't begrudge it. You'll get yours soon enough. Here we have some suggestions from a motley crew of three or four or maybe more or fewer.
Mouse Number One is suffering an identity crisis, whimpering "I don't really know who I am anymore and I really hoped to have this information after modifying my profile."
Mouse Number Twö müses „While Amazon is trying to upsell me their service, I am wondering how their localization infrastructure must be implemented to enable errors like \".“
Mouse Number N is almost ready to square off with some back office programmer. "A very secure PIN on an obligatory wooden table."
Mouse Number 502 has gone bad. "This could be a gateway to something better. I think I'll apply."
Finally, an anon from some summer morn sent us this some time ago and it confused me so much I sat on it. I've never figured out what he was on about, so maybe you can explain it to me. Perhaps his snarky comment will be clueful? "When you don't know how to screenshot, print it out and scan it back in," he said.
[Advertisement] Plan Your .NET 9 Migration with Confidence
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!
CodeSOD: Tis the Season(al Release)
We recently asked for some of your holiday horror stories. We'll definitely take more, if you've got them, but we're going to start off with Jessica, who brings us not so much a horror as an omen.
Jessica writes:
I work for a company in the UK which writes legal software for law firms.
This raises the question what illegal software for law firms might look like, but I understand her meaning.
In the UK, there is a system called "Legal aid", where law firms can give free legal services to people who otherwise couldn't afford it and get reimbursed from the government for their time. As one might imagine from such a system, there is a lot of bureaucracy and a lot of complexity.
The core of the system is a collection of billing rate sheets, billing codes for the various kinds of services, and a pile of dense forms that need to be submitted. Every few months, something in that pile changes. Sometimes it's something small, like moving a form field to a different alignment, or one police station changed its rate sheet. Sometimes it's a wholesale recalibration of the entire system. Sometimes it's new forms, or altered forms, or forms getting dropped from the workflow entirely (a rare, but welcome event).
The good news is that the governing body sends out plenty of notice about the changes before they go into effect. Usually a month, sometimes two, but it's enough time for Jessica's company to test the changes and update their software as needed.
That's what Jessica is working on right now: taking the next batch of changes and preparing the software for the change, a change that's scheduled to deploy a month from now. It's plenty of work, but it's not a hair-on-fire crisis.
Then, during a team meeting, her manager asked: "I haven't booked my holiday yet, and wanted to double check who is available to work over Christmas?"
"Why would anyone need to work over Christmas?" one of the senior developers asked.
Why? Well, one of the larger rate sheets was going to publish new changes on December 22nd, and the changes were expected to be rolled out to all clients on the same day.
"It's just a data update," the manager said weakly. "What could go wrong?"
Probably nothing, that was certainly true. But even just rolling out a change to payment rates was not a risk free endeavor. Sometimes the source data had corrections which needed to be rolled out with great haste, sometimes customers weren't prepared to handle the changed rates, sometimes there were processing pipelines which started throwing out weird bounds errors because something buried in the rate sheet caused a calculation to return absurd results. And sometimes the governing body said "it's just changes to rates," but then includes changes to forms along with it. There wasn't a single rate sheet update that didn't involve providing some degree of support, even if that support was just fielding questions from confused users who didn't expect the change.
The point is that Jessica's team, and every other vendor supplying software to lawfirms in the UK, will be making a major production update three days before Christmas. And from that, providing support to all their customers through that Christmas window.
The only good news? Jessica just started at this job. While the newbie is usually the person who gets stuck with the worst schedule, she's so new that she's not prepared to handle the support work alone, yet. So it's one of the senior devs who gets to work through the holiday this year.
Jessica writes:
Thank god it's not me this year!
Oh, don't worry Jessica. There will be plenty more holidays next year.
[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!The Modern Job Hunt: Part 2
(Read Part 1 here)
By the 10-month mark of her job search, Ellis still lacked full-time employment. But she had accumulated a pile of knowledge and advice that she wished she'd started with. She felt it was important to share, in hopes that even one person might save some time and sanity:
- This is your new normal. Take time to grieve your loss and accept this change. Act and plan as if this situation were permanent. It isn't, of course, but it does you no good to think that surely you won't be at this long, you'll definitely have a job by such and such time, etc. Minimize your expenses now: instead of viewing it as deprivation, make a game out of creative frugality. Do whatever it takes to preserve your physical and mental health. Remember your inherent worth as a living being, and rest assured that this does not diminish it in any way. Know that thousands, if not millions, are in this boat with you: people with decades of experience, people fresh out of school, people with doctorates, they're all struggling. Some have been searching for years and have cast thousands of applications out there, to no avail. This isn't meant to scare or depress you. This is to properly set your expectations.
- Take the time to decide what you REALLY want for the future. You might have to fight against a lot of panic or other tough emotions to do this, but it would help to consider your current assets, your full range of options, and your heart's desires first. What did you like/dislike about your past experience that might inform the sorts of things you would/wouldn't want in whatever comes next? Is there anything you've dreamed of doing? Is there any sort of work that calls to you, that you gladly would do even if you weren't paid for it? Are you thinking that maybe this might be the time to start your own business, go freelance, return to school, change careers, or retire? This may be a golden opportunity to pivot into something new and exciting.
- Work your network. This is the cheat code, as most jobs are not obtained by people coming in cold. If a friend or coworker can give you a referral somewhere, you might get to skip a lot of hassle. As your job search lengthens, keep telling people that you're available.
- Go back to basics. Don't assume that because you've job-hunted before that you know what you're doing with respect to resumes, cover letters, interviews, portfolios, LinkedIn, etc. AI has completely changed everything. If you can get help with this stuff, by all means do so. Before paying for anything, look for free career counseling and job leads offered by nonprofits or other agencies near you. Your library might offer career help and free courses through platforms like LinkedIn Learning. You can find tons of tutorials on YouTube for skills you may be lacking, and you can often audit college courses for free.
- Ask for help. Get comfortable asking for whatever you may need. Most people want to help you, if they only knew how. Times like these are when you learn how wonderful people can be.
- Streamline your search. Fake job postings are rampant. Avoid looking for or applying to jobs through LinkedIn. Check sites like Welcome to the Jungle, Jobgether, and Remote Rocketship for leads (feel free to share your own favorite lead-generators in the comments). Once you find a promising listing, go to the company's website and look for it there. Assuming you find it, save yourself some time by skipping straight down to the Qualifications list. Do you satisfy all or most of those? If not, move on. If so, read the rest of the listing to see if it's a good match for you. Apply directly from the company's website, making sure your resume contains their list of must-haves word-for-word. AI will be evaluating your application long before any human being touches it.
- Beware scams. They are everywhere and take all forms. For instance, you may be tempted to apply to one of those AI-training jobs for side cash, but they will simply take your data and ghost you. Scammers also come at you by phone, email, and text. If it's unsolicited and/or too good to be true, it's probably fake. Always verify the source of every job-related communication.
- If you make it to the interviewing stage, expect a gauntlet of at least four to get through. Thanks, Google! If you're in need of a laugh, take an interview lesson from the all-time champion himself, George Costanza.
- You will face rejection constantly. Even if you view rejection as a positive force in your life for growth, it's still hard to take sometimes. Whatever you feel is valid.
- Ghosting is also normal. Even for those who've already been through several rounds of interviews, who felt like they really nailed it, or were even told to expect an offer. Prepare yourself.
Even though Ellis had resolved to look more seriously into remaining freelance, she hadn't been able to help throwing resumes at full-time job postings whenever a promising one surfaced. After all, some income and benefits would really help while figuring out the freelance thing, right?
Unfortunately, she got so caught up in this tech writing assignment, that interview, that her new adventure wasn't just relegated to the side, it was fully ejected from her consciousness. And for what? For companies that forgot all about her when she failed to meet all of their mysterious criteria. Poof. Hours of study and research up in smoke, hopes crushed.
Clutter accumulated on her computer and around her normally neat house. Every time she looked at one of these objects out in the open, her brain spun off 14 new threads. I have to take that downstairs ... Oh! There's no room in that drawer, I'll have to clean it out first. Also gotta clean my eyeglasses while I'm there. No wait, I was gonna write that email! Oh wait, tomorrow, I'm going to the gym today. Lemme write this down. Where's my laptop?
Along with stress came resentment and frustration from a sense of never accomplishing anything. Finally, Ellis forced herself to stop and pay attention. She'd gone seriously off-course. Her feelings were telling her that if she persisted in this job search, she'd be betraying some deep truth about herself. What was it, exactly?
Being a storyteller, it helped her to consider her own tale. She realized that at the end of her life, she absolutely would not be satisfied saying, "Man, I'm glad I left all those software manuals to the world." With whatever time she had left, she wanted to center her gifts first and foremost, never again relegating them to the periphery. She wanted to leverage them to help others, find ways to build community, serve the world in ways that mattered deeply to her and aligned with her values. She wanted to further free herself from society's shoulds and have-tos.
Her last full-time gig would've given her five weeks of vacation. During her job search, how many weeks of vacation had she given herself? Zero, aside from those forced by illness or injury.
- Do better than Ellis. Give yourself regular sanity breaks. Take in sunlight and nature whenever possible. Do things that make your soul feel alive, that make you wonder where the time went. Laugh! Enjoy "funemployment."
Ellis was blessed with financial savings that had carried her thus far. From Thanksgiving to New Year's, she resolved to give herself the gift of unplugged soul-searching. How did she want to live the rest of her life? How would she leave the world better than how she'd found it? These were the questions she would be asking herself.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.CodeSOD: The Article
When writing software, we like our code to be clean, simple, and concise. But that loses something, you end up writing just some code, and not The Code. Mads's co-worker wanted to make his code more definite by using this variable naming convention:
public static void addToListInMap(final Map theMap, final String theKey, final Object theValue) { List theList = (List) theMap.get(theKey); if (theList == null) { theList = new ArrayList(); theMap.put(theKey, theList); } theList.add(theValue); }This Java code clearly is eschewing generic types, which is its own problem, and I also have to raise concerns about a map of lists; I don't know what that structure is for, but there's almost certainly a better way to do it.
But of course, that's not why we're here. We're here to look at the variable names. This developer did this all the time, a bizarre version of Hungarian notation. Did the developer attend The Ohio State? (Since all jokes are funnier when you explain them, Ohio State insists on being referred to with the definite article, which sounds weird, and yes, that's not the weirdest thing about American Football, but it's weird).
I worry about what happens when one function takes in two maps or two keys? theKey and theOtherKey? Or do they get demoted to aKey and anotherKey?
But I am left wondering: what is theValue of this convention?
[Advertisement] Keep all your packages and Docker containers in one place, scan for vulnerabilities, and control who can access different feeds. ProGet installs in minutes and has a powerful free version with a lot of great features that you can upgrade when ready.Learn more.CodeSOD: The Magic Array
Betsy writes:
I found this snippet recently in a 20-year-old RPG program.
Ah, yes, twenty years ago, RPG, that means this was written in the 1970s. What? No. That can't be right? That's how long ago?
Joking about my mortality aside, in the early oughts, most of the work around RPG was in keeping old mainframe systems from falling over. That entirely new code was being written, that new projects were being started twenty years ago is not a surprise, but it's unusual enough to be remarkable. That said, the last release of RPG was in 2020, so it clearly keeps on keeping on.
In any case, this developer, we'll call them "Stephen", needed to create an array containing the numbers 12 through 16.
Let's take a peek at the code.
D RowFld S 3 0 DIM(5) D X S 3 0 D Y S 3 0 C EVAL X = 12 C FOR Y = 1 TO %Elem(RowFld) C EVAL RowFld(y) = X C EVAL X = X + 1 C ENDFORThe first three lines create some variables: RowFld, which is an array containing 5 elements, and will hold our offsets. X and Y are going to hold our numeric values.
We set X equal to 12, then we start a for loop from 1 to the length of our RowFld. We set the element at that index equal to X, then increment X.
The code is awkward, but is not exactly the WTF here. This particular program displays a file and a subfile, and these values are used to position the cursor inside that subfile. The array is never iterated over, the array is never modified, the array would 100% be better managed as a set of constants, if you didn't want to have magic numbers littering your code. More than that, the location of the subfile on the screen has never changed. And let's be fair, this didn't get rid of magic numbers, it just made them one through five, instead of 12 through 16, as the indexes in the array are just as arbitrary.
In other words, there's no point to this. Even if the specific version of RPG didn't have constants variables that you handle like constants would be fine (my checks on the documentation seem to imply that CONST first appeared in version RPG IV 7.2, which makes it look like circa 2016).
But there's one more bit of weirdness here. Stephen had several years of experience with RPG, and all of that experience was from the "free-format" era of RPG. You see, way back in 2001, RPG finally freed itself from its dependency on punchcards, and started allowing you to write code as just strings of text, without requiring certain things to exist in certain columns. This was a generally positive enhancement, and Betsy's team immediately adopted it, as did everyone running the latest versions of RPG. All new development was done using the "free-format" style, so they could write code like normal people. They even had a conversion tool which would do some simple string manipulation to convert legacy RPG programs into the modern style, and had basically abandoned the legacy style without looking back.
Except for Stephen, who insisted on the column oriented format. Who protested when anyone tried to modify their code to modernize it at all. "Oh, we used free-format at my last job," Stephen said when pressed, "but it's confusing and columns are just cleaner and more readable."
Eventually, someone else wrote a program that absorbed all the functionality in Stephen's program. Stephen kept plugging away at it for a few years afterwards, because a handful of users also refused to migrate to the new tool. But eventually they left the company for one reason or another, and Stephen found himself without users for his work, and left with them.
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.Error'd: A Horse With No Name
Scared Stanley stammered "I'm afraid of how to explain to the tax authority that I received $NaN."
Our anonymous friend Anon E. Mous wrote "I went to look up some employee benefits stuff up and ... This isn't a good sign."
Regular Michael R. is not actually operating under an alias, but Ovostake doesn't know.
Graham F. gloated "I'm glad my child 's school have followed our naming convention for their form groups as well!"
Adam R. is taking his anonymous children on a roadtrip to look for America. "I'm planning a trip to St. Louis. While trying to buy tickets for the Gateway Arch, I noticed that their ticketing website apparently doesn't know how to define adults or children (or any of the other categories of tickets, for that matter)."
[Advertisement] Plan Your .NET 9 Migration with Confidence
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!
CodeSOD: Pawn Pawn in in Game Game of of Life Life
It feels like ages ago, when document databases like Mongo were all the rage. That isn't to say that they haven't stuck around and don't deliver value, but gone is the faddish "RDBMSes are dead, bro." The "advantage" they offer is that they turn data management problems into serialization problems.
And that's where today's anonymous submission takes us. Our submitter has a long list of bugs around managing lists of usernames. These bugs largely exist because the contract developer who wrote the code didn't write anything, and instead "vibe coded too close to the sun", according to our submitter.
Here's the offending C# code:
[JsonPropertyName("invitedTraders")] [BsonElement("invitedTraders")] [BsonIgnoreIfNull] public InvitedTradersV2? InvitedTraders { get; set; } [JsonPropertyName("invitedTradersV2")] [BsonElement("invitedTradersV2")] [BsonIgnoreIfNull] public List<string>? InvitedTradersV2 { get; set; }Let's start with the type InvitedTradersV2. This type contains a list of strings which represent usernames. The field InvitedTradersV2 is a list of strings which represent usernames. Half of our submitter's bugs exist simply because these two lists get out of sync- they should contain the same data, but without someone enforcing that correctly, problems accrue.
This is made more frustrating by the MongoDB attribute, BsonIgnoreIfNull, which simply means that the serialized object won't contain the key if the value is null. But that means the consuming application doesn't know which key it should check.
For the final bonus fun, note the use of JsonPropertyName. This comes from the built-in class library, which tells .NET how to serialize the object to JSON. The problem here is that this application doesn't use the built-in serializer, and instead uses Newtonsoft.JSON, a popular third-party library for solving the problem. While Newtonsoft does recognize some built-in attributes for serialization, JsonPropertyName is not among them. This means that property does nothing in this example, aside from add some confusion to the code base.
I suspect the developer responsible, if they even read this code, decided that the duplicated data was okay, because isn't that just a normal consequence of denormalization? And document databases are all about denormalization. It makes your queries faster, bro. Just one more shard, bro.
[Advertisement] Keep all your packages and Docker containers in one place, scan for vulnerabilities, and control who can access different feeds. ProGet installs in minutes and has a powerful free version with a lot of great features that you can upgrade when ready.Learn more.The Thanksgiving Shakedown
On Thanksgiving Day, Ellis had cuddled up with her sleeping cat on the couch to send holiday greetings to friends. There in her inbox, lurking between several well wishes, was an email from an unrecognized sender with the subject line, Final Account Statement. Upon opening it, she read the following:
Dear Ellis,
Your final account statement dated -1 has been sent to you. Please log into your portal and review your balance due totaling #TOTAL_CHARGES#.
Payment must be received within 30 days of this notice to avoid collection. You may submit payment online via [Payment Portal Link] or by mail to:
Chamberlin Apartments
123 Main Street
Anytown US 12345
If you believe there is an error on your account, please contact us immediately at 212-555-1212.
Thank you for your prompt attention to this matter.
Chamberlin Apartments
Ellis had indeed rented an apartment managed by this company, but had moved out 16 years earlier. She'd never been late with a payment for anything in her life. What a time to receive such a thing, at the start of a long holiday weekend when no one would be able to do anything about it for the next 4 days!
She truly had so much to be grateful for that Thanksgiving, and here was yet more for her list: her broad technical knowledge, her experience working in multiple IT domains, and her many years of writing up just these sorts of stories for The Daily WTF. All of this added up to her laughing instead of panicking. She could just imagine the poor intern who'd hit "Send" by mistake. She also imagined she wasn't the only person who'd received this message. Rightfully scared and angry callers would soon be hammering that phone number, and Ellis was further grateful that she wasn't the one who had to pick up.
"I'll wait for the apology email!" she said out loud with a knowing smile on her face, closing out the browser tab.
Ellis moved on physically and mentally, going forward with her planned Thanksgiving festivities without giving it another thought. The next morning, she checked her inbox with curious anticipation. Had there been a retraction, a please disregard?
No. Instead, there were still more emails from the same sender. The second, sent 7 hours after the first, bore the subject line Second Notice - Outstanding Final Balance:
Dear Ellis,
Our records show that your final balance of #TOTAL_CHARGES# from your residency at your previous residence remains unpaid.
This is your second notice. Please remit payment in full or contact us to discuss the balance to prevent your account from being sent to collections.
Failure to resolve the balance within the next 15 days may result in your account being referred to a third-party collections agency, which could impact your credit rating.
To make payment or discuss your account, please contact us at 212-555-1212 or accounting@chamapts.com.
Sincerely,
Chamberlin Apartments
The third, sent 6 and a half hours later, threatened Final Notice - Account Will Be Sent to Collections.
Dear Ellis,
Despite previous notices, your final account balance remains unpaid.
This email serves as final notice before your account is forwarded to a third-party collections agency for recovery. Once transferred, we will no longer be able to accept payment directly or discuss the account.
To prevent this, payment of #TOTAL_CHARGES# must be paid in full by #CRITICALDATE#.
Please submit payment immediately. Please contact 212-555-1212 to confirm your payment.
Sincerely,
Chamberlin Apartments
It was almost certainly a mistake, but still rather spooky to someone who'd never been in such a situation. There was solace in the thought that, if they really did try to force Ellis to pay #TOTAL_CHARGES# on the basis of these messages, anyone would find it absurd that all 3 notices were sent mere hours apart, on a holiday no less. The first two had also mentioned 30 and 15 days to pay up, respectively.
Suddenly remembering that she probably wasn't the only recipient of these obvious form emails, Ellis thought to check her local subreddit. Sure enough, there was already a post revealing the range of panic and bewilderment they had wrought among hundreds, if not thousands. Current and more recent former tenants had actually seen #TOTAL_CHARGES# populated with the correct amount of monthly rent. People feared everything from phishing attempts to security breaches.
It wasn't until later that afternoon that Ellis finally received the anticipated mea culpa:
We are reaching out to sincerely apologize for the incorrect collection emails you received. These messages were sent in error due to a system malfunction that released draft messages to our entire database.
Please be assured of the following:
The recent emails do not reflect your actual account status.
If your account does have an outstanding balance, that status has not changed, and you would have already received direct and accurate communication from our office.
Please disregard all three messages sent in error. They do not require any action from you.
We understand that receiving these messages, especially over a holiday, was upsetting and confusing, and we are truly sorry for the stress this caused. The issue has now been fully resolved, and our team has worked with our software provider to stop all queued messages and ensure this does not happen again.
If you have any questions or concerns, please feel free to email leasing@chamapts.com. Thank you for your patience and understanding.
All's well that ends well. Ellis thanked the software provider's "system malfunction," whoever or whatever it may've been, that had granted the rest of us a bit of holiday magic to take forward for all time.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.CodeSOD: The Destination Dir
Darren is supporting a Delphi application in the current decade. Which is certainly a situation to be in. He writes:
I keep trying to get out of doing maintenance on legacy Delphi applications, but they keep pulling me back in.
The bit of code Darren sends us isn't the largest WTF, but it's a funny mistake, and it's a funny mistake that's been sitting in the codebase for decades at this point. And as we all know, jokes only get funnier with age.
FileName := DestDir + ExtractFileName(FileName); if FileExists(DestDir + ExtractFileName(FileName)) then begin ... end;This code is inside of a module that copies a file from a remote server to the local host. It starts by sanitizing the FileName, using ExtractFileName to strip off any path components, and replace them with DestDir, storing the result in the FileName variable.
And they liked doing that so much, they go ahead and do it again in the if statement, repeating the exact same process.
Darren writes:
As Homer Simpson said "Lather, rinse, and repeat. Always repeat."
[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!CodeSOD: Formula Length
Remy's Law of Requirements Gathering states "No matter what the requirements document says, what your users really wanted was Excel." This has a corrolary: "Any sufficiently advanced Excel file is indistingushable from software."
Given enough time, any Excel file whipped up by any user can transition from "useful" to "mission critical software" before anyone notices. That's why Nemecsek was tasked with taking a pile of Excel spreadsheets and converting them into "real" software, which could be maintained and supported by software engineers.
Nemecsek writes:
This is just one of the formulas they asked me to work on, and not the longest one.
Nemecsek says this is a "formula", but I suspect it's a VBA macro. In reality, it doesn't matter.
InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0). InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart).Losses = calcLossesInPart(InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0). InitechNeoDTActivePart(0).RatedFrequency, InitechNeoDTMachineDevice. InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0). InitechNeoDTActivePartPart(iPart).RadialPositionToMainDuct, InitechNeoDTMachineDevice. InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0). InitechNeoDTActivePartPart(iPart).InitechNeoDTActivePartPartSectionContainer(0). InitechNeoDTActivePartPartSection(0).InitechNeoDTActivePartPartConductorComposition(0).IsTransposed, InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0). InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartSectionContainer(0).InitechNeoDTActivePartPartSection(0). InitechNeoDTActivePartPartConductorComposition(0).ParallelRadialCount, InitechNeoDTMachineDevice. InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0). InitechNeoDTActivePartPart(iPart).InitechNeoDTActivePartPartSectionContainer(0). InitechNeoDTActivePartPartSection(0).InitechNeoDTActivePartPartConductorComposition(0). ParallelAxialCount, InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0). InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartSectionContainer(0).InitechNeoDTActivePartPartSection(0). InitechNeoDTActivePartPartConductorComposition(0).InitechNeoDTActivePartPartConductor(0).Type, InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0). InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartSectionContainer(0).InitechNeoDTActivePartPartSection(0). InitechNeoDTActivePartPartConductorComposition(0).InitechNeoDTActivePartPartConductor(0). DimensionRadialElectric, InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0). InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartSectionContainer(0).InitechNeoDTActivePartPartSection(0). InitechNeoDTActivePartPartConductorComposition(0).InitechNeoDTActivePartPartConductor(0). DimensionAxialElectric + InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0). InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartSectionContainer(0).InitechNeoDTActivePartPartSection(0). InitechNeoDTActivePartPartConductorComposition(0).InitechNeoDTActivePartPartConductor(0).InsulThickness, getElectricConductivityAtTemperatureT1(InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0). InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartSectionContainer(0).InitechNeoDTActivePartPartSection(0). InitechNeoDTActivePartPartConductorComposition(0).InitechNeoDTActivePartPartConductor(0). InitechNeoDTActivePartPartConductorRawMaterial(0).ElectricConductivityT0, InitechNeoDTMachineDevice. InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0). InitechNeoDTActivePartPart(iPart).InitechNeoDTActivePartPartSectionContainer(0). InitechNeoDTActivePartPartSection(0).InitechNeoDTActivePartPartConductorComposition(0). InitechNeoDTActivePartPartConductor(0).InitechNeoDTActivePartPartConductorRawMaterial(0).MaterialFactor, InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0).InitechNeoDTActivePart(0). InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartSectionContainer(0).InitechNeoDTActivePartPartSection(0). InitechNeoDTActivePartPartConductorComposition(0).InitechNeoDTActivePartPartConductor(0). InitechNeoDTActivePartPartConductorRawMaterial(0).ReferenceTemperatureT0, InitechNeoDTMachineDevice. ReferenceTemperature), LayerNumberRatedVoltage, InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0). InitechNeoDTActivePart(0).InitechNeoDTActivePartPartContainer(0).InitechNeoDTActivePartPart(iPart). InitechNeoDTActivePartPartLayerContainer(0),InitechNeoDTMachineDevice.InitechNeoDTActivePartContainer(0). InitechNeoDTActivePart(0).RFactor)Line breaks added to try and keep horizontal scrolling sane. This arguably hurts readability, in the same way that beating a dead horse arguably hurts the horse.
This may not be the longest one, but it's certainly painful. I do not know exactly what this is doing, and frankly, I do not want to.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!Error'd: On the Dark Side
...matter of fact, it's all dark.
Gitter Hubber checks in on the holidays: "This is the spirit of the Black Friday on GitHub. That's because I'm using dark mode. Otherwise, it would have a different name… You know what? Let's just call it Error Friday!"
"Best get typing!" self-admonishes.
Jason G.
Suffering a surfeit of snark, he proposes
"Not sure my battery will last long enough.
Finally, quantum resistant security.
I can't remember my number after the 5000th digit.
" Any of those will do just fine.
Don't count Calle L. out. "This is for a calorie tracking app, on Thanksgiving. Offer was so delicious it wasn't even a number any more! Sadly it did not slim the price down more than expected."
"Snow and rain and rain and snow!" exclaims Paul N. "Weather so astounding, they just had to trigger three separate notifications at the same time."
It's not a holiday for everyone though, is it? Certainly not for Michael R. , who is back with a customer service complaint about custom deliveries. "I am unlucky with my deliveries. This time it's DPD. "
[Advertisement] Plan Your .NET 9 Migration with Confidence
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!
Classic WTF: Teleported Release
Matt works at an accounting firm, as a data engineer. He makes reports for people who don’t read said reports. Accounting firms specialize in different areas of accountancy, and Matt’s firm is a general firm with mid-size clients.
The CEO of the firm is a legacy from the last century. The most advanced technology on his desk is a business calculator and a pencil sharpener. He still doesn’t use a cellphone. But he does have a son, who is “tech savvy”, which gives the CEO a horrible idea of how things work.
Usually, this is pretty light, in that it’s sorting Excel files or sorting the output of an existing report. Sometimes the requests are bizarre or utter nonsense. And, because the boss doesn’t know what the technical folks are doing, some of the IT staff may be a bit lazy about following best practices.
This means that most of Matt’s morning is spent doing what is essentially Tier 1 support before he gets into doing his real job. Recently, there was a worse crunch, as actual support person Lucinda was out for materinity leave, and Jackie, the one other developer, was off on vacation on a foreign island with no Internet. Matt was in the middle of eating a delicious lunch of take-out lo mein when his phone rang. He sighed when he saw the number.
“Matt!” the CEO exclaimed. “Matt! We need to do a build of the flagship app! And a deploy!”
The app was rather large, and a build could take upwards of 45 minutes, depending on the day and how the IT gods were feeling. But the process was automated, the latest changes all got built and deployed each night. Anything approved was released within 24 hours. With everyone out of the office, there hadn’t been any approved changes for a few weeks.
Matt checked the Github to see if something went wrong with the automated build. Everything was fine.
“Okay, so I’m seeing that everything built on GitHub and everything is available in production,” Matt said.
“I want you to do a manual build, like you used to.”
“If I were to compile right now, it could take quite awhile, and redeploying runs the risk of taking our clients offline, and nothing would be any different.”
“Yes, but I want a build that has the changes which Jackie was working on before she left for vacation.”
Matt checked the commit history, and sure enough, Jackie hadn’t committed any changes since two weeks before leaving on vacation. “It doesn’t looked like she pushed those changes to Github.”
“Githoob? I thought everything was automated. You told me the process was automated,” the CEO said.
“It’s kind of like…” Matt paused to think of an analogy that could explain this to a golden retriever. “Your dishwasher, you could put a timer on it to run it every night, but if you don’t load the dishwasher first, nothing gets cleaned.”
There was a long pause as the CEO failed to understand this. “I want Jackie’s front-page changes to be in the demo I’m about to do. This is for Initech, and there’s millions of dollars riding on their account.”
“Well,” Matt said, “Jackie hasn’t pushed- hasn’t loaded her metaphorical dishes into the dishwasher, so I can’t really build them.”
“I don’t understand, it’s on her computer. I thought these computers were on the cloud. Why am I spending all this money on clouds?”
“If Jackie doesn’t put it on the cloud, it’s not there. It’s uh… like a fax machine, and she hasn’t sent us the fax.”
“Can’t you get it off her laptop?”
“I think she took it home with her,” Matt said.
“So?”
“Have you ever seen Star Trek? Unless Scotty can teleport us to Jackie’s laptop, we can’t get at her files.”
The CEO locked up on that metaphor. “Can’t you just hack into it? I thought the NSA could do that.”
“No-” Matt paused. Maybe Matt could try and recreate the changes quickly? “How long before this meeting?” he asked.
“Twenty minutes.”
“Just to be clear, you want me to do a local build with files I don’t have by hacking them from a computer which may or may not be on and connected to the Internet, and then complete a build process which usually takes 45 minutes- at least- deploy to production, so you can do a demo in twenty minutes?”
“Why is that so difficult?” the CEO demanded.
“I can call Jackie, and if she answers, maybe we can figure something out.”
The CEO sighed. “Fine.”
Matt called Jackie. She didn’t answer. Matt left a voicemail and then went back to eating his now-cold lo mein.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.Announcements: We Want Your Holiday Horrors
As we enter into the latter portion of the year, folks are traveling to visit family, logging off of work in hopes that everything can look after itself for a month, and somewhere, someone, is going to make the choice "yes, I can push to prod on Christmas Eve, and it'll totally work out for me!"
Over the next few weeks, I'm hoping to get a chance to get some holiday support horrors up on the site, in keeping with the season. Whether it's the absurd challenges of providing family tech support, the last minute pushes to production, the five alarm fires caused by a pointy-haired-bosses's incompetence, we want your tales of holiday IT woe.
So hit that submit button on the side bar, and tell us who's on Santa's naughty list this year.
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.Tales from the Interview: Interview Smack-Talk
In today's Tales from the Interview, our Anonymous submitter relates their experience with an anonymous company:
I had made it through the onsite, but along the way I had picked up some toxic work environment red flags. Since I had been laid off a couple months prior, I figured I wasn't in a position to be picky, so I decided I would still give it my best shot and take the job if I got it, but I'd continue looking for something better.
Then they brought me back onsite a second time for one final interview with 2 senior managers. I went in and they were each holding a printout of my resume. They proceeded to go through everything on it. First they asked why I chose the university I went to, then the same for grad school, which was fine.
Then they got to my first internship. I believe the conversation went something like this:
Manager: "How did you like it?"
Me: "Oh, I loved it!"
Manager: "Were there any negatives?"
Me: "No, not that I can think of."
Manager: "So it was 100% positive?"
Me: "Yep!"
And then they got to my first full-time job, where the same manager repeated the same line of questioning but pushed even harder for me to say something negative, at one point saying "Well, you left for (2nd company on my resume), so there must have been something negative."
I knew better than to bad-mouth a previous employer in an interview, it's like going into a first date and talking smack about your ex. But what do you do when your date relentlessly asks you to talk smack about all your exes and refuses to let the subject turn to anything else? This not only confirmed my suspicions of a toxic work environment, I also figured *they* probably knew it was toxic and were relentlessly testing every candidate to make sure they wouldn't blow the whistle on them.
That was the most excruciatingly awkward interview I've ever had. I didn't get the job, but at that point I didn't care anymore, because I was very, very sure I didn't want to work there in the long term.
I'm glad Subby dodged that bullet, and I hope they're in a better place now.
It seems like this might be some stupid new trend. I recently bombed an interview where I could tell I wasn't giving the person the answer on their checklist, no matter how many times I tried. It was a question about how I handled it when someone opposed what I was doing at work or gave me negative feedback. It felt like they wanted me to admit to more fur-flying drama and fireworks than had ever actually occurred.
I actively ask for and welcome critique on my writing, it makes my work so much better. And if my work is incorrect and needs to be redone, or someone has objections to a project I'm part of, I seek clarification and (A) implement the requested changes, (B) explain why things are as they are and offer alternate suggestions/solutions, (C) seek compromise, depending on the situation. I don't get personal about it.
So, why this trend? Subby believed it was a way to test whether the candidate would someday badmouth the employer. That's certainly feasible, though if that were the goal, you'd think Subby would've passed their ordeal with flying colors. I'm not sure myself, but I have a sneaking suspicion that the nefarious combination of AI and techbro startup culture have something to do with it.
So perhaps I also dodged a bullet: one of the many things I'm grateful for this Thanksgiving.
Feel free to share your ideas, and any and all bullets you have dodged, in the comments.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.CodeSOD: The Map to Your Confession
Today, Reginald approaches us for a confession.
He writes:
I've no idea where I "copied" this code from five years ago. The purpose of this code was to filter out Maps and Collections Maybe the intention was to avoid a recursive implementation by an endless loop? I am shocked that I wrote such code.
Well, that doesn't bode well, Reginald. Let's take a look at this Java snippet:
/** * * @param input * @return */ protected Map rearrangeMap(Map input) { Map retMap = new HashMap(); if (input != null && !input.isEmpty()) { Iterator it = input.keySet().iterator(); while (true) { String key; Object obj; do { do { if (!it.hasNext()) { } key = (String) it.next(); } while (input.get(key) instanceof Map); obj = input.get(key); } while (obj instanceof Boolean && ((Boolean) obj).equals(Boolean.FALSE)); if (obj != null) { retMap.put(key, obj); return retMap; } } } else { return retMap; } }The first thing that leaps out is that this is a non-generic Map, which is always a code smell, but I suspect that's the least of our problems.
We start by verifying that the input Map exists and contains data. If the input is null or empty, we return it. In our main branch, we create an iterator across the keys, before ethering a while(true) loop. So far so bad
Then we enter a pair of nested do loops. Which definitely hints that we've gone off the edge of the map here. In the inner most loop, we do a check- if there isn't a next element in the iterator, we… do absolutely nothing. Whether there is or isn't an element, we advance to the next element, risking a NoSuchElementException. We do this while the key points to an instance of Map. As always, an instanceof check is a nauseating code stench.
Okay, so the inner loop skips across any keys that point to maps, and throws an exception when it gets to the end of the list.
The surrounding loop skips over every key that is a boolean value that is also false.
If we find anything which isn't a Map and isn't a false Boolean and isn't null, we put it in our retMap and return it.
This function finds the first key that points to a non-map, non-false value and creates a new map that contains only that key/value. Which it's a hard thing to understand why I'd want that, especially since some Map implementations make no guarantee about order. And even if I did want that, I definitely wouldn't want to do that this way. A single for loop could have solved this problem.
Reginald, I don't think there's any absolution for this. Instead, my advice would be to install a carbon monoxide detector in your office, because I have some serious concerns about whether or not your brain is getting enough oxygen.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!CodeSOD: Copied Homework
Part of the "fun" of JavaScript is dealing with code which comes from before sensible features existed. For example, if you wanted to clone an object in JavaScript, circa 2013, that was a wheel you needed to invent for yourself, as this StackOverflow thread highlights.
There are now better options, and you'd think that people would use them. However, the only thing more "fun" than dealing with code that hasn't caught up with the times is dealing with developers who haven't, and still insist on writing their own versions of standard methods.
const objectReplace = (oldObject, newObject) => { let keys = Object.keys(newObject) try { for (let key of keys) { oldObject[key] = newObject[key] } } catch (err) { console.log(err, oldObject) } return oldObject }It's worth noting that Object.entries returns an array containing both the keys and values, which would be a more sensible for this operation, but then again, if we're talking about using correct functions, Object.assign would replace this function.
There's no need to handle errors here, as nothing about this assignment should throw an exception.
The thing that really irks me about this though is that it pretends to be functional (in the programming idiom sense) by returning the newly modified value, but it's also just changing that value in place because it's a reference. So it has side effects, in a technical sense (changing the value of its input parameters) while pretending not to. Now, I probably shouldn't get too hung up on that, because that's also exactly how Object.assign behaves, but dammit, I'm going to be bothered by it anyway. If you're going to reinvent the wheel, either make one that's substantially worse, or fix the problems with the existing wheel.
In any case, the real WTF here is that this function is buried deep in a 15,000 line file, written by an offshore contract team, and there are at least 5 other versions of this function, all with slightly different names, but all basically doing the same thing, because everyone on the team is just copy/pasting until they get enough code to submit a pull request.
Our submitter wonders, "Is there a way to train an AI to not let people type this?"
No, there isn't. You can try rolling that boulder up a hill, but it'll always roll right back down. Always and forever, people are going to write bad code.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!Error'd: Untimely
Sometimes, it's hard to know just when you are. This morning, I woke up to a Macbook that thinks it's in Paris, four hours ago. Pining for pain chocolate. A bevy of anonyms have had similar difficulties.
First up, an unarabian anonym observes "They say that visiting Oman feels like traveling back in time to before the rapid modernization of the Arab states. I just think their eVisa application system is taking this "time travel" thing a bit too far... "
Snecod, an unretired (anteretired?) anonym finds it hard to plan when the calendar is unfixed. "The company's retirement plan was having a rough time prior to Second June." Looks like the first wtf was second March.
And an unamerican anonym sent us this (uh, back in first March) "Was looking to change the cable package I have from them. Apparently my discounts are all good until 9th October 1930, and a second one looking good until 9th January 2024."
On a different theme, researcher Jennifer E. exclaimed "Those must have been BIG divorces! Guy was so baller Wikipedia couldn’t figure out when he divorced either of these women." Or so awful they divorced him continuously.
Finally, parsimonious Greg L. saved this for us. "I don't remember much about #Error!, but I guess it was an interesting day."
[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.
CodeSOD: Invalid Route and Invalid Route
Today's representative line comes from Capybara James (most recently previously). It's representative, not just of the code base, but of Goodhart's Law: when a measure becomes a target, it ceases to be a good measure. Or, "you get what you measure".
If, for example, you decide that code coverage metrics are how you're going to judge developers, then your developers are going to ensure that the code coverage looks great. If you measure code coverage, then you will get code coverage- and nothing else.
That's how you get tests like this:
Mockito.verify(exportRequest, VerificationModeFactory.atLeast(0)).failedRequest(any(), any(), any());This test passes if the function exportRequest.failedRequest is called at least zero times, with any input parameters.
Which, as you might imagine, is a somewhat useless thing to test. But what's important is that there is a test. The standards for code coverage are met, the metric is satisfied, and Goodhart marks up another win on the board.
[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.CodeSOD: Are You Mocking Me?
Today's representative line comes from Capybara James (most recently previously). It's representative, not just of the code base, but of Goodhart's Law: when a measure becomes a target, it ceases to be a good measure. Or, "you get what you measure".
If, for example, you decide that code coverage metrics are how you're going to judge developers, then your developers are going to ensure that the code coverage looks great. If you measure code coverage, then you will get code coverage- and nothing else.
That's how you get tests like this:
Mockito.verify(exportRequest, VerificationModeFactory.atLeast(0)).failedRequest(any(), any(), any());This test passes if the function exportRequest.failedRequest is called at least zero times, with any input parameters.
Which, as you might imagine, is a somewhat useless thing to test. But what's important is that there is a test. The standards for code coverage are met, the metric is satisfied, and Goodhart marks up another win on the board.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!Using an ADE: Ancient Development Environment
One of the things that makes legacy code legacy is that code, over time, rots. Some of that rot comes from the gradual accumulation of fixes, hacks, and kruft. But much of the rot also comes from the tooling going unsupported or entirely out of support.
For example, many years ago, I worked in a Visual Basic 6 shop. The VB6 IDE went out of support in April, 2008, but we continued to use it well into the next decade. This made it challenging to support the existing software, as the IDE frequently broke in response to OS updates. Even when we started running it inside of a VM running an antique version of Windows 2000, we kept running into endless issues getting projects to compile and build.
A fun side effect of that: the VB6 runtime remains supported. So you can run VB6 software on modern Windows. You just can't modify that software.
Greta has inherited an even more antique tech stack. She writes, "I often wonder if I'm the last person on Earth encumbered with this particular stack." She adds, "The IDE is long-deprecated from a vendor that no longer exists- since 2002." Given the project started in the mid 2010s, it may have been a bad choice to use that tech-stack.
It's not as bad as it sounds- while the technology and tooling is crumbling ruins, the team culture is healthy and the C-suite has given Greta wide leeway to solve problems. But that doesn't mean that the tooling isn't a cause of anguish, and even worse than the tooling- the code itself.
"Some things," Greta writes, "are 'typical bad'" and some things "are 'delightfully unique' bad."
For example, the IDE has a concept of "designer" files, for the UI, and "code behind" files, for the logic powering the UI. The IDE frequently corrupts its own internal state, and loses the ability to properly update the designer files. When this happens, if you attempt to open, save, or close a designer file, the IDE pops up a modal dialog box complaining about the corruption, with a "Yes" and "No" option. If you click "No", the modal box goes away- and then reappears because you're seeing this message because you're on a broken designer file. If you click "Yes", the IDE "helpfully" deletes pretty much everything in your designer file.
Nothing about the error message indicates that this might happen.
The language used is a dialect of C++. I say "dialect" because the vendor-supplied compiler implements some cursed feature set between C++98 and C++11 standards, but doesn't fully conform to either. It's only capable of outputting 32-bit x86 code up to a Pentium Pro. Using certain C++ classes, like std::fstream, causes the resulting executable to throw a memory protection fault on exit.
Worse, the vendor supplied class library is C++ wrappers on top of an even more antique Pascal library. The "class" library is less an object-oriented wrapper and more a collection of macros and weird syntax hacks. No source for the Pascal library exists, so forget about ever updating that.
Because the last release of the IDE was circa 2002, running it on any vaguely modern environment is prone to failures, but it also doesn't play nicely inside of a VM. At this point, the IDE works for one session. If you exit it, reboot your computer, or try to close and re-open the project, it breaks. The only fix is to reinstall it. But the reinstall requires you to know which set of magic options actually lets the install proceed. If you make a mistake and accidentally install, say, CORBA support, attempting to open the project in the IDE leads to a cascade of modal error boxes, including one that simply says, "ABSTRACT ERROR" ("My favourite", writes Greta). And these errors don't limit themselves to the IDE; attempting to run the compiler directly also fails.
But, if anything, it's the code that makes the whole thing really challenging to work with. While the UI is made up of many forms, the "main" form is 18,000 lines of code, with absolutely no separation of concerns. Actually, the individual forms don't have a lot of separation of concerns; data is shared between forms via global variables declared in one master file, and then externed into other places. Even better, the various sub-forms are never destroyed, just hidden and shown, which means they remember their state whether you want that or not. And since much of the state is global, you have to be cautious about which parts of the state you reset.
Greta adds:
There are two files called main.cpp, a Station.cpp, and a Station1.cpp. If you were to guess which one owns the software's entry point, you would probably be wrong.
But, as stated, it's not all as bad as it sounds. Greta writes: "I'm genuinely happy to be here, which is perhaps odd given how terrible the software is." It's honestly not that odd; a good culture can go a long way to making wrangling a difficult tech stack happy work.
Finally, Greta has this to say:
We are actively working on a .NET replacement. A nostalgic, perhaps masochistic part of me will miss the old stack and its daily delights.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.