The Daily WTF
Error'd: Some Southern Exposure
Never let it be said that we at TDWTF dish it out and can't take it.
Morgan immediately dished "I'm not sure what date my delivery will arrive but I will {PlanToBeAtHomeWhenItDoes}. "
Barry M. reported some non-fatal HTML exposure, no chance of frostbite. "Just in case you couldn’t tell it’s a paragraph."
Hungry Bob loves berries and potaotes. "Not sure why I get these point-less receipts each time I check out, but I love the exposed formatting. This one has a bonus misspelling too. "
The kind of exposure B.J.H. is flirting with could be a lot more dangerous than Bob's. B.J. found weather.com pining for Vegas. No surprise with those temperatures! "I first thought it was a one-time glitch, but reloading weather.com gave me a different bad result. They tried a fancy rolling display but didn't know when to stop. This happens in Firefox, the issue doesn't show up in Chrome. I looked in the console to see if that showed the problem but there was a continuous stream of WTF messages, both in Firefox and Chrome. "
And finally, in frist place, Dave A. dared "It has been said that smart people learn from their mistakes, but wise people learn from other people's mistakes. There have been so many time travel WTFs on TDWTF that the wise@$$&$ there have apparently learn from them... how to do it. (And to head off the obvious time-zone possibility, I'm in US-East, and it was 10:34 AM.) "
[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: Validation Trimmed Away
Grace sends us, in her words, "the function that validates the data from the signup form for a cursed application."
It's more than one function, but there are certainly some clearly cursed aspects of the whole thing.
function trimStr(v) { return typeof v === "string" ? v.trim() : v; }This function, itself, isn't cursed, but it certainly represents a bad omen. Take any type of input, and if that input happens to be a string, return the trimmed version. Otherwise, return the input unchanged. I've got good news and bad news about this omen: the good news is that it isn't used in most of the code that follows, and the bad news is that it is used in some of the code that follows.
The next function builds a validation schema using the yup library, and we'll take this one in chunks, since it's long.
function buildSchema() { // Common string with trim transform const t = () => yup .string() .transform((val) => (typeof val === "string" ? val.trim() : val)) .nullable();See, I promised that the trimStr function wasn't used in most of the code- because they just copy/pasted its body where they needed it.
let emailField = yup .string() .transform((val) => (typeof val === "string" ? val.trim().toLowerCase() : val)) .nullable() .required("email is required"); emailField = emailField.test("email-format", "email is invalid", (v) => { if (!v) return false; // required above // Simple email format validation return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i.test(v); });I assume t above is meant to be a common base transformation, so you don't have to constantly rewrite the trim functionality. Though this isn't precisely a trim- it also canonicalizes the address to lower case. That will likely work most of the time, but while the domain portion of an email address is case insensitive, the address part of it is not- Remy@somesite.com and remy@somesite.com could be different addresses.
They also make the email field both nullable and required, which is an interesting choice. Not one they're confident about, as they also check that the required field is actually populated in their test function. Then they do a regex to validate the email address, which it's worth noting that email addresses shouldn't be validated by regexes, but also yup already includes an email validation, so none of this is necessary.
let passwordField = yup.string().nullable().required("password is required"); passwordField = passwordField .test( "password-min-length", "password must be at least 8 characters", (v) => !!v && v.length >= 8 ) .test( "password-alpha-num", "password must contain letters and numbers", (v) => !!v && (/[A-Za-z]/.test(v) && /\d/.test(v)) ); let confirmPasswordField = yup.string().nullable().required("confirmPassword is required"); confirmPasswordField = confirmPasswordField.test( "passwords-match", "password and confirmPassword do not match", function (v) { const pwd = this.parent.password; if (!v && !pwd) return false; // both empty => invalid if (!v || !pwd) return true; // required rules will handle return v === pwd; } );Passwords limited to alphanumeric is a choice. A bad one, certainly. Again we also see the pattern of nullable required fields.
let telephoneField = t().required("telephone is required"); telephoneField = telephoneField.test("telephone-digits", "telephone is invalid", (v) => { if (!v) return false; const digits = (v.match(/\d/g) || []).length; return digits >= 7; });Oh, at least on phone numbers they use that common base transformation. Again, they're not using the built-in features of yum which can already validate phone numbers, but hey, at least they're making sure that there are at least seven digits, which probably works in some places. Not everywhere, but some places.
const schema = yup.object().shape({ firstName: t().required("firstName is required").max(100, "firstName too long"), lastName: t().required("lastName is required").max(100, "lastName too long"), companyName: t().required("companyName is required").max(150, "companyName too long"), telephone: telephoneField, email: emailField, product: t().max(150, "product too long"), password: passwordField, confirmPassword: confirmPasswordField, affiliateId: t(), visitorId: t(), }); return schema; }And here we finish constructing the schema, and look at that- we do use that base transformation a few more times here.
How do we use it?
function validateSignupPayload(payload = {}) { // Normalize input keys to match schema: support email/emailAddress and telephone/phoneNumber const normalized = { firstName: trimStr(payload.firstName), lastName: trimStr(payload.lastName), companyName: trimStr(payload.companyName), telephone: trimStr(payload.telephone) || trimStr(payload.phoneNumber), email: (trimStr(payload.email) || trimStr(payload.emailAddress) || "").toLowerCase(), product: trimStr(payload.product), password: typeof payload.password === "string" ? payload.password : payload.password || undefined, confirmPassword: typeof payload.confirmPassword === "string" ? payload.confirmPassword : payload.confirmPassword || undefined, affiliateId: trimStr(payload.affiliateId), visitorId: trimStr(payload.visitorId), }; const schema = buildSchema(); try { const cleaned = schema.validateSync(normalized, { abortEarly: false, stripUnknown: true }); return { errors: [], cleaned }; } catch (e) { const errors = Array.isArray(e.errors) ? e.errors : ["Invalid arguments"]; // Still return partial cleaned data from normalization return { errors, cleaned: normalized }; } }Here, we "normalize" the inputs, which repeats most of the logic of how we validate the inputs. Mostly. This does have the added benefit of ensuring that the password fields could be undefined, which is not null. More fun, to my mind, is that the input form is clearly inconsistent about the naming of fields- is it telephone or phoneNumber? email or emailAddress?
I agree that this is cursed, less in the creeping dread sense, and more in the "WTF" sense.
.comment { border: none; } [Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!CodeSOD: NUrll
Grace was tarcking down some production failures, which put her on the path to inspecting a lot of URLs in requests. And that put her onto this blob of code:
app.get( ( [ "/api/ddm/getProjectList", ":dueDate", ":status", ":userAssignedId", ":managerID", ":clientID", ":projectHeaderID", ":tagId", ":companyId", ":clientGroup", ":isDefault", ":dateRange", ":dateToFilter", ":tagIds", ":statusIds", ":repeatValues", ":engagementID?", ":completionDate?" ] .join( "/" ) ), ddmDboardCtrl.getProjectList );This defines a route in ExpressJS for handling GET requests. And it defines the route such that every single parameter on the request is contained in the path portion of the URL. That raises questions about why you need seventeen parameters to fulfill your request and what that means for our API design, but it's even worse than it looks: most of those parameters are allowed to be null.
That means the request looks like this:
GET /api/ddm/getProjectList/null/null/null/null/878778/null/null/2049/null/null/null/null/null/null/null/3532061?For bonus point, the developer responsible for that awful API also has a "special" way for dealing with possibly empty returns:
( fs.readdirSync( `${ GLOBAL_DIRECTORY_PATH }` ) || ( [ ] ) ) .map( ( function( moduleName ){ return ( path.resolve( ( `${ GLOBAL_DIRECTORY_PATH }/${ moduleName }` ) ) ); } ) )This code calls reddirSync and in case that returns null, ||s the result with an empty array. Only one problem: readdirSync never returns null. It returns an empty array when there are no results.
Also, this indenting is as submitted, which… what is even happening?
This developer has a strange relationship with nulls- defending against them when they're not a risk, spamming them into URLs. They have gazed too long into the null, and the null gazes back into them.
[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: Well Timed Double Checking
Last week's out of order logging reminded Adam R of a similar bug he encountered once.
The log files looked like this:
[2026-01-14 16:40:12.999802][process_name][42][DEBUG][somefilename:01234] A thing happened [2026-01-14 16:40:12.999997][process_name][42][DEBUG][somefilename:01235] Another thing happened [2026-01-14 16:40:12.000031][process_name][42][DEBUG][somefilename:01236] A third thing happened [2026-01-14 16:40:13.000385][process_name][42][DEBUG][somefilename:01237] A fourth thing happenedNote the timestamp on the third log line: it's out of order. But as you can get from Adam's highly anonymized messages, it's actually in the correct order- it's the third thing that happened, and it's the third log line. So clearly, something has gone off with calculating the timestamp.
Now, if you want to ask your OS for time with microsecond precision, you can call gettimeofday, which will populate a timeval struct. That gives you seconds/microseconds since the epoch. gmtime can then be used to convert the seconds portion into something more readable. This is pretty standard stuff- how could someone screw it up?
void Logger::log(const char* message, int level, const char* filename, int line) { time_t now = time(); struct tm* now_tm = gmtime(&now); struct timeval now_tv; gettimeofday(&now_tv, NULL); char buffer[1024]; // I've simplified this to a fixed-size buffer for expository purposes, but the code DID handle overflow and dynamically resizing the buffer correctly snprintf(buffer, sizeof(buffer), "[%04d-%02d-%02d %02d:%02d:%02d.%06d][%s][%s][%s][%32s:%05d] %s\n", now_tm->tm_year + 1900, now_tm->tm_mon + 1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, now_tv->tv_usec, get_process_name(), get_thread_id(), log_level_string(level), filename, line, message); write_to_log_file(buffer); }This C++ function is reconstructed as Adam remembers it. The first four lines highlight the problem: they check the time twice. The call to time() returns the number of seconds since the epoch, which they then convert into a readable time using gmtime. Then they use gettimeofday to get the seconds/microseconds since the epoch. When they print, they use the values from time for every field but microseconds, and then use the microseconds from gettimeofday.
They check the clock twice, and shockingly, get different values each time. And when the clock ticks are near a second boundary, the microseconds can roll back over to zero, creating a situation where log entries appear to go backwards in time.
The fix was simple: just check the time once.
Adam writes:
My suspicion is that this logging function started out printing only seconds, and then someone realized "Hey, wouldn't it be useful to add microseconds to here as well?" and threw in the extra call to gettimeofday() without thinking about it hard enough.
That's a pretty solid suspicion. Adam can't confirm it, because he doesn't work there anymore, and has no access to their source control, and even if he did, the project has been through multiple source control migrations which destroyed or otherwise mangled the history, leaving the root cause as always and forever a mystery.
[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.Marking Territory
There's something about hierarchical arrangements that makes top-down interference utterly irresistible to many managers and executives. Writers may also experience similar strife with their editors, a phenomenon Robert Heinlein described with the perfect metaphor: "After he pees in it himself, he likes the flavor much better."
Sometimes, a leader leverages their hard-won wisdom and experience to steer a project onto a better path. But, all too often, someone's imagined wisdom and starving ego force a perfectly good train off the rails.
Today, our friend and long-time submitter Argle shares an example of the latter:
Between 2017 and the end of 2023, I worked with a contracting firm. The work was quite varied, and I generally liked all the clients I had to deal with. One of those was Regional Western Electric. RWE was a good company, and the engineers I worked most closely with were guys I'd happily drink beer with. The project itself was a bit of a WTF: it was a transformer design program written in BASIC running on DOS (from circa 1988) that they wished to modernize.
While it's possible to write good BASIC code, that generally doesn't happen, and this project was typical. Aside from having a horrendous user interface, their 10 base transformer designs started as a single program and bloated to 10 programs, all sharing variables g1 through g99 and g1$ through g99$. At some point, they got a language update, so full-length names dotted the program, and a few line numbers went away.
Thankfully, they didn't want us to fix the program: they wanted it replaced as web application for their intranet. This proved that there ARE smart engineers and management.
My job was to convert all the math from BASIC to C#. I was more the math guy than the other senior programmer who wanted this to be our second big project in Angular. (The first was an internal project.) This worked well, though I did ask at the start if it wasn't wiser just to have me get together with their engineers at a marker board and just figure out everything directly. There was some discussion about this, and one engineer remarked that we'll probably look back and regret not following my suggestion, but at least going the "conversion" route let us compare old output to new.
Since this was a fact, we forged ahead. The catch with this was that I had to replicate all the content errors, and there were many. A sorted table of wires had one sorted out of place. A lengthy magnetic field calculation was negated by multiplying by a global variable that was always 0. The code was littered with *1.1 or *1.05 to add 10% or 5% fudge factors to one specific design, then left in the code. As this progressed, the project went from unmanageable code to which nothing new could be added (they had newer equipment which couldn't be figured into designs) [into something manageable].
This is the happy part of the story.
The unhappy part is what happened to my co-worker. While I had a lovely base class for the transformers and happy virtual functions making the designs slick, he had something similar working in Angular. The CSS was great and designed by our house designer (who was good at his job), the components were perfect ... the whole thing was a showcase project.
Then came the meeting to discuss the aforementioned additions that everyone was looking forward to. For the first time, their IT director joined one of the meetings. He looked over everything, then declared that he didn't want to learn Typescript and Angular, and then insisted that the whole front-end be rewritten in MVC.
The company was paid by the hour, so the owner didn't mind this, but you could almost see the smoke rising from my co-worker's head as he spent weeks on the rewrite.
As for the IT director, he never stuck his nose in the project again. Never maintained it, and retired around the time I added some of the new features.
Sadly, the period of inflation ate into any budget they might have had to move on to the next big phase of the project, and I've moved on to another company.
It's just a shame what one person throwing his weight around can do to a project.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!Error'd: Chicken Feed
"Zero balance due now!" shouted davethepirate "To be fair, I had disputed a charge on a bill and they finally relented which should have actually resulted in them owing me $1.01, but I'm happy with the win." I'm sure yarr.
This beats Cory Booker," commented nja for reasons I don't begin to understand. "This show is damned good, and there sure is a lot to say on the matter, but 419,951 more hours?"
"What an effective CAPTCHA," cooed Peter G. "They forgot to ask for doodles, sign language, and squirrel noises." I think the trick here is that if you actually DO manage it correctly, they know you're a robot.
"Eight Characters means what, again??" cried Mark R. For myself, I'm ecstatic they used "symbol" instead of "special character".
"For the past several years, I've enjoyed free identity theft monitoring as a result of multiple data breaches of various third-party services. That's finally running out now, but I'm not sure if it's in 30 days or in 5 days," grumbles Adam R.
Which brings us to the let's talk about me portion of this
episode.
This week, I received
a letter from the University of Phoenix, by whom I
briefly was employed TEN YEARS AGO,
informing me that various bits of sensitive personal data
had been leaked in their Oracle EBS breach last year.
By way of apology, they offered me
one of these almost useless subscriptions.
By now, everyone must have three or four of these
"complimentary one-year subscriptions" simultaneously. The
vendors of these services know that a significant
portion of the breached public never bother to sign up. Cost: $0.
For those who do, it's a customer acquisition
funnel: this year is paid by [latest sloppy bungler] and then they
hit you up for a recurring premium.
I strongly suspect that the various "identity protection
services" come swarming out of the trees the moment they hear of some breach, and are very, very, competitive on price. How much do you suppose they pay for the new customer acquisition? Less than whatever statutory damages the UofP will have to pay the government?
Anybody who has first-hand knowledge of the terms of a post-breach contract for victim services, please let us know.
CodeSOD: A Sudden Tern
Matthias sends us what he calls the "tern of the century". Which, before I share it with you: bad news, it's just a regular bad ternary. But it remains bad in interesting ways, so it's definitely worth talking about. But let's not oversell it.
private static String getOrderTypeCode(CreateOrderRequest order) { return !StringUtils.isBlank(order.getOrderParams().getReceivingCompanyFoo()) && ORDR_TP_DQQ_FOO.equals(order.getOrderParams().getOrderType()) ? ORDR_TP_DQQ_BAR_CDE : order.GetOrderParams().getOrderType().getOrderTypeCode(); }This function takes an order, and inspects it to figure out the type of order it represents. The logic is this: if the receiving company has the "foo" property set, and the order is already set to type "Foo", then we return the "bar" code (not a bar code- Matthias is using "foo" and "bar" as anonymous placeholders), otherwise we return whatever order type code that was set on the order type.
Now, I've left this all on one line, as it is in the codebase, which certainly helps with the WTF feeling of the whole thing. Protip: don't write ternaries that need to wrap across three lines to be readable.
This is messy and unreadable, but by ternary standards it's just regular bad. No, the thing that is driving me up the wall is the code-golfy constant names. ORDR is short for ORDER. CDE is CODE. I have no idea what TP or DQQ stand for. But I see no good reason to turn every constant into the name of some droid loitering around Jabba's Palace in Star Wars just to save a few keystrokes.
I'd be less bothered if the abbreviations were more cryptic, but just dropping a middle vowel from "ORDER" sits in this bizarre half-point between "exists as meaningless jargon, good luck" and "I wrote something readable". I'd be less annoyed if it were more of a WTF.
[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: Going Through Time
Philipp H was going through some log files generated by their CI job to try and measure how long certain steps in the process took. He took the obvious path of writing code to read the logfiles, parse out the timestamps, and then take the difference between them.
Everything worked fine, until for certain steps, a negative timestamp was reported:
> -1 day, 23:59:59.713529 section cleanup_file_variablesOn one hand, having CI jobs finish before they were started was incredibly convenient, and certainly would make their integration much faster. Plus, they could probably get some funding to find the exotic matter which allowed the existence of the wormhole that clearly allowed this inversion of causality.
On the other hand, this was probably a bug.
Here's a snippet from the logfile:
> 2025-08-18T14:49:40.748000Z 00O+section_start:1755528580:cleanup_file_variables > 2025-08-18T14:49:40.754100Z 00O+Cleaning up project directory and file based variables > 2025-08-18T14:49:40.461529Z 00O section_end:1755528580:cleanup_file_variablesThe format is a timestamp with nanoseconds, followed by a stream identifier (STDOUT vs. STDERR) followed by the actual message.
If you look at the nanoseconds, you might spot something odd: the third timestamp occurs before the previous ones. The obvious conclusion one could draw is that this is a concurrency issue, and the log entries are getting printed out of order. Philipp's naive solution won't work, and he'll need to sort the timestamps before doing the calculation.
But that conclusion is as obvious as it is wrong. Look more closely at those trailing zeroes. They seem a little odd, don't they? Something off?
Here's the Go code which generates the timestamps:
t := now() // time.RFC3339 doesn't add nanosecond precision, and time.RFC3339Nano doesn't // use a fixed length of precision. Whilst we could use a custom format, this // is slower, as Go as built-in optimizations for RFC3339. So here we use the // non-nano version, and then add nanoseconds to a fixed length. Fixed length // is important because it makes the logs easier for both a human and machine // to read. t.AppendFormat(l.bufStream[:0], time.RFC3339) // remove the 'Z' l.bufStream = l.bufStream[:l.timeLen-fracs-additionalBytes] l.bufStream[len(l.bufStream)-1] = '.' // replace 'Z' for '.' // ensure nanoseconds doesn't exceed our fracs precision nanos := t.Nanosecond() / int(math.Pow10(9-fracs)) // add nanoseconds and append leading zeros leadingZeros := len(l.bufStream) l.bufStream = strconv.AppendInt(l.bufStream, int64(nanos), 10) leadingZeros = fracs - (len(l.bufStream) - leadingZeros) for i := 0; i < leadingZeros; i++ { l.bufStream = append(l.bufStream, '0') } // add 'Z' back l.bufStream = append(l.bufStream, 'Z') // expand back to full header size l.bufStream = l.bufStream[:l.timeLen+4]This appends the timestamp to the stream, then replaces the timezone indicator (Z) with a .. In calculates the number of nanoseconds, then the number of required leading zeros to get the fixed length. Then it appends the nanoseconds, followed by the leading zeroes, making them trailing zeroes. Whoops.
Now, this Go code doesn't come from some in-house job, but from a major vendor of CI/CD tooling, which is what makes this tiny little bug a WTF. But hey, it's very well commented.
Philipp writes:
We're talking about a modern language like Go here and that really make we wonder, if they do not have a built-in function to format integers to strings with left-padding...
While I'm not a Go expert, I can actually answer this question: Go has made the explicit choice to keep the standard library as small as possible, to the point where loads of things you think should be there aren't. Whether that extends to formatting functions, I'm not certain, but it results of a conscious design choice.
Setting aside whether or not one agrees with this design choice, there's an argument to be had over it. It's not, on its face, automatically wrong.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!CodeSOD: A Pirate's Confession
Today we have a true confession from Carl W. It has the benefit of being in R, which means that at a glance, I just assume "eh, looks fine to me." I guess I'm turning into Jimbo.
But let's dig into it. Carl's first snippet is this:
for(kk in 1:length(thematch)) { if(length(thematch)==0) break # actual code }"What WAS I thinking?" Carl asks.
You were thinking two things: you were thinking you wanted to iterate across a list, and you were thinking you didn't want to do anything if the list was empty. That these wires got crossed is natural- but sure, this isn't something that should end up in production code. The WTF is less the code itself, and more whatever allowed it to get released.
Carl's next snippet is described as "Yes, let's invert logicals as many times as possible."
slice <-rep(0,length(newxx)) slicelog<-as.logical(cuts[j]<=newyy & newyy<=cuts[j+1]) is.na(slice)<-!slicelogBecause R is weird, <- is one of the assignment operators (it also uses =, but for different purposes, and don't ask me to explain the difference), and because people like to have fun, it also has an -> operator (so the assignee is on the right side of the expression), and <<- and ->> versions which muck with scope in interesting ways.
In this example, the rep function replicates a value (0, in this case) length(newxx) times. So that gives us an array of zeros.
R supports broadcasting operations, so cuts[j] is an array and newyy is also an array (vector, if we're using R parlance), and by comparing two arrays we get an array of boolean values. Which we then pass to as.logical which converts an array into an array of boolean values.
Finally, in R, the NA value is their version of null. Thus is.na returns an array which is true if the original input held a null at that index, and false otherwise. Which is definitely going to be an array of falses, because slice holds an array of 0s. We just made it. Then we assign to the return value of that function. This is syntactically valid, but as you can imagine, it doesn't actually make sense- we just discard the result, at least based on me trying this in an R REPL.
Carl writes:
While the function containing these snippets was definitely a victim of "code it and design the requirements later," I can't believe that even Beginner Me wrote stuff that horrifying. But, it works perfectly so it ain't gonna get fixed.
Ah, that last sentence there, that is a dark truth. And it's important to note, it works perfectly: for now. But the world and runtime environment change. And someday, another developer will receive this code, and wonder, much like Carl, what the hell was going on when it was written.
In any case, Carl, consider yourself absolved. If it's stupid and it works, well, it's still stupid, but these WTFs are small and mostly self-contained.
Remember: code is a liability and starts accruing cruft and tech-debt the instant it's released. The functionality that code delivers is the asset, but that asset is inextricably tied to the code, which encodes assumptions about the world which, even if they were true to begin with, become increasingly false as the world changes.
Also, if you haven't figured out the headline, and because jokes are funnier when you explain them, this is clearly about a pirate's second favorite programming language, ARRRR. Why their second favorite? Because their first love will always be the C.
[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.The Modern Job Hunt: A Side Quest
Over the past few months, Ellis has been sharing the challenges of the modern job hunt. As I'm one week into my new gig, after a weird and protracted search, I thought I'd add my two cents, because kids: it's nasty out there, for sure.
So, for starters, I wrapped up my time working on space robots, and have shifted over to farm robots. That's right, I'm a farmer now. While it may be less glamorous, the business prospects, and thus the prospects of continued employment, are better. That said, I'm working with a startup so I wouldn't say it's all that safe. Still, good change for now, and maybe I'll talk a bit more about what that's like at some point. But that's not where I want to focus today.
While my job search was shorter than many folks- about two and a half months- it was still a difficult trek. The biggest thing to my advantage is that embedded software engineers are in low supply relative to their demand. Also, the training data for embedded software remains a very small proportion of AI training sets, so LLMs remain pretty bad at it. It's a good subfield to be in, right now.
And yet, the market still sucks.
Now, I'm an old person, which means I distribute resumes more as a k-selector than an r-selector. I wasn't sending out hundreds of resumes, but I did send out dozens, which honestly is much more than I usually do by an order of magnitude. Of the dozens I sent out, I scored four interviews, one of which was a cold call from a recruiter, which we'll talk about.
Getting RailedOne interview was with a company in the railway industry. I spoke with their internal recruiter, and we discussed what kind of work I was doing, and what I'd like to be doing. It went well, and led to a call with the team. And that's where I found out they were hiring for a management position, not an engineering position. I was wildly unprepared for that conversation, and both sides of the conversation felt weird and awkward about it. Our expectations were misaligned, and by the end of it, neither I nor they wanted to continue the conversation. The commute would have been terrible, so no real loss from my perspective, but boy, am I annoyed with that recruiter.
Nuke ItA second conversation, which I'm not counting as an interview, since I only spoke with the recruiter, was with a local contracting company. They handle a lot of government contracts (up to and including work on nuclear weapons), and were looking to staff up. The conversation with the recruiter went well, she had a number of positions (not involving nuclear weapons) that she wanted to recommend me for. She warned me that, as it was the end of the year, things might not move until early this year. I was fine with that. Things did move, though, right in the middle of the holidays I got an email saying the organization wasn't going to move forward with my candidacy. No further insight was provided, but given how enthused the recruiter was, I was mildly surprised. But I have a suspicion about what happened, based on two other positions.
Fancy RobotsOne position was for another local robotics company. They had a brand spanking new office, had just matured their main product into something really polished and sell-able, had an on-site cafeteria and were eager to hire. Their interview process was a bit involved with a number of phone screens in addition to the whole day on-site, but everyone was great to work with. They had big scaling plans, and there were going to be plenty of positions behind me to bring on.
"We're going to get you your offer letter Monday or Tuesday of next week," their internal recruiter told me. "It's just our leadership team is at a summit, and we need them back before we send out offers."
That was a weird thing to hear. It seems to me that you should be able to hire an engineer without clearing it with leadership, but what do I know? Monday came and went. Tuesday came. The recruiter called me back: "So, we're not hiring anyone for any position at this time." She was extremely apologetic, related how much the team was disappointed that they couldn't bring me on, and that if positions re-opened I was at the top of the list for hiring. I found out later that the company did a round of layoffs, and the recruiter (who was great through the whole process) was a victim of them.
Left ColdA different position came from a cold call from a third-party recruiter. Now, I don't normally give third-party recruiters the time of day. I think, as an industry, they are parasites and scum, and generally more interested in their commission than making either employees or employers happy. But this position was doing embedded work for high-end audio-visual equipment for broadcasters, and was a massive raise. Oh, and it was 100% remote.
I verified that this company was real, actually shipped products, and had a decent reputation in the industry. So with that, I decided to hear the recruiter out.
"They're really eager to hire," he said. "So the plan is this: we're going to set up one single panel interview for an hour. Everyone who needs to be involved in the decision will be there. After that, they'll review, and give you a thumbs up thumbs down ASAP."
That was a terrifyingly short interview, for both sides, but I've gotten some great jobs that way, so I was down for it. It went great, everyone was happy. Everyone on the call wanted to move forward with hiring. There was just one problem: not everyone who was supposed to be making the decision was there. A member of their leadership team missed the interview. And they couldn't move forward without this gentleman's thumbs up.
This lead to weeks of back and forth with the recruiter. They went from "eager to hire" to the recruiter saying "I don't know, I can't get anyone on the phone."
Once again, the end of the story is that they opted to not hire for any roles, and yes, a round of layoffs ensued.
On ReadWhile we're talking about recruiter cold calls, I got a cold text from a recruiter. I didn't particularly like that on its own, but hey, it's the modern era, everyone communicates via text. Worse, it was a significant down-level and salary decrease. So I replied back that I wasn't interested.
I understand, and your experience certainly warrants consideration for a higher salary
That was the reply, along with a glaze about my skills and the opportunity for growth. It was obsequious, sycophantic, and unfocused. I exchanged a few more messages and the conversation started to get repetitive. And you know where this is going.
That's impressive and very relevant! Working on critical systems for guidance and navigation pairs excellently with this role. Here at Smith & Nephew, you'll need similar rigor developing algorithms for surgical robotics, where precision is key for patient outcomes. Your experience handling highly reliable systems and your background ensures you have what it takes for such critical work. Any platforms or microcontrollers you're particularly excited about using?
Normally for job-search stuff, I'd conceal the source or be vague. I haven't named any of the companies that strung me along because they were at least trying to hire me. But Smith & Nephew deserves to be named and shamed. Look at that: that is 100% chatbot. The recruiter can't even be bothered to do their job, they have to outsource it to a chatbot. And if you're not convinced, I replied: "This conversation can continue when it's not with a chatbot."
I understand your preference for more personal interaction. Thank you for chatting with me! I'll make sure someone from the senior recruiting team gets in touch with you to continue the conversation on your terms.
I have not heard from someone in the senior recruiting team, which is a shame, because I have many rude things I'd like to say to them. It's one thing to get a form-letter email, but a cold-text from a bot that just nags you for replies and tries to keep the conversation going is an entirely new level of "I don't care about the candidate experience at all".
On the Funny FarmThe process with the farming robots company was about as you'd expect. A few phone interviews, a most-of-the-day on-site. Two separate technical screens looking for different things. A fun exercise was "pretend this is a pull request I submitted to you, do a code review with me."
After the on-site, the director of operations (who was acting as the recruiter) let me know: an offer is coming, but there's some paperwork they had to do on their side, so it'd be a few days. And boy howdy, after the job search I'd had up to that point, I expected "needing to do paperwork" to drag out for weeks and then hear they weren't hiring. But that's not what happened, and I've changed jobs.
While it's only been a week, it's so far, so good. There's certainly a lot of work to do here, and they've got plans to expand their embedded footprint that will make me pretty pivotal to their future hardware revisions, and so it's all exciting.
For those still hunting, and especially those between jobs: good luck. You're not alone, and you're not crazy for thinking things are bad out there right now. They're awful. But you're great.
[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.Error'd: Twofers
This week's episode is brought to you by the number two.
"Two Error'ds in two months from these guys!" exclaim'd Thad H. Frist was this, about which Thad snarked "Canada got rid of the penny years ago. I guess the 407ETR took that literally."
Shortly thereafter Thad then followed up with " I'm thinking no one proofreads their emails. " Obviously.
"How is the LiMu website like the Hotel California?" Barry M. riddles. Is it because they both have a hauntingly melodic jingle?
Following up the named shame (thank you) Barry asks Ameriprise "What if I'm not the owner?"
John S. commented of the following interaction "A google search for my local Home Depot here in Ontario suggests that someone is a fan of The Prisoner, and/or that Home Depot is a free man." He included a reviews link which didn't illuminate me.
"Yes, Home Depot, you're right," replied Keith G. Mic drop emoji here.
[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: The Review
Frequent contributor Argle Bargle (recently, or even in last week's Errord) works with a programmer called "Jimbo". Jimbo is a solid co-worker and a good programmer. He has more tenure at the company than Argle, which means Jimbo is who Argle goes to when he has questions.
Recently, Argle worked his way through a rather complicated bit of code. It involved passing data between two different languages inside of a real-time system. Much of its functionality was opaque and complicated, so Argle wrote literal paragraphs of documentation explaining what the code did, how to invoke it, what the gotchas might be, and how to avoid them.
Argle expected the pull request to take some time to complete, but Jimbo was on the spot and approved it quickly. Another reviewer chimed in, and in went the code.
The next day, Argle and Jimbo were working together through some fresh code which depended on that request.
"Wait a second," Jimbo asked, "how does this data make it from one thread to another? It's mallocd. I don't see how it gets past that boundary."
"You realize," Argle replied, "I documented this, in detail, in the code you reviewed yesterday afternoon."
"Oh, that? I didn't read it."
"That defeats the purpose of code reviews."
Jimbo shrugged. "I'm sure it's fine."
Argle writes:
I have worked in two aerospace firms in my life and there are days I wonder that I risk setting foot in an airplane.
[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.Un-break-able
Ever feel like it'd all fall to pieces if you so much as turned your head? In the comments section of our article seeking your seasonal horror stories, Wayne shared a holiday WTF of a different sort that's too good not to share:
Not a holiday problem, but a me being on holiday problem.
I was the sole SQL Server database admin back in the '90s for a pretty good-sized police department. Everything ran pretty darn smooth, and I took a week off, probably to go to ComicCon. I left VERY specific instructions to call me if there was a problem.
We had a consultant working with us, I was never clear on what he was doing, but he sat in his office every day typing away and looking busy. Apparently he was writing mods to our payroll pre-process system. Police payroll is complicated because pretty much every rank has a different union, and contract, that changes how things are paid out: if you hold or are paid overtime, how sick leave works, it's all pretty weird. Or was at the time. It was wonderful getting the Peoplesoft programmer saying "We can't do that!" when they wanted us to put our preprocess into their system.
ANYWAY, this system ran an extract every week which produced two files, overtime and leave, which was then sneakernetted down the street to the mainframe. On pay weeks, there was an absolute time window for when that 3.5" floppy had to be there as it could hold up mainframe jobs. We ran the extract at about noon and the disk was there by 1. Very solid.
Until I went on vacation.
Consultant in his infinite wisdom pushed his changes to our payroll database on an extract day. And crashed the database, making it impossible to run the extract. And it was payroll week. AND they didn't call me. He spent 4-5 hours MANUALLY UNDOING HIS CHANGES. And holding up the mainframe processing schedules.
Had they called me, I could have told them that the system automatically backed itself up, and they could have done a rollback to undo his changes and reverted to a good state and run the extract.
Come to think of it, I never did find out what his modifications were supposed to do.
It's baffling why Wayne was never called, but I assume it's because the consultant had assured everyone that he had the situation under control. He was either in a mad, panicked rush to fix what he'd broken, or, he was calm and fully confident in his own abilities.
Doth pride goeth before the missed paycheck?
[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: No Yes
It's common to see code in the form of if (false == true). We get a fair bit of it in our inbox, and we generally don't post it often, because, well, it's usually just a sign that someone generated the code. There's a WTF in that, somewhere, but there's not much to say about the code, beyond, "Don't generate code, pass data from backend to frontend instead."
But Nicholas sends us one that shows a little more of interest in it.
if ('N' == 'Y') { document.getElementById("USERID").disabled=true; document.getElementById("PASSWORD").disabled=true; }Again, this is almost certainly being generated by the backend and sent to the frontend. I mean, it might be someone manually disabling a block of code by writing an if that'll never be true, but probably not in this case.
And what this tells us is that the backend is getting inputs, probaly from some sort of option field, and treating them as booleans. Y and N are clearly meant to be "yes" and "no", aka "true" and "false", but we're taking the stringly typed approach on the backend.
For future developers, I reiterate: send data to the frontend, so your 'if' looks more like: if(backendData.userSelectedOption=="Y"), or at the very least if you're going to evaluate the boolean expression, evaluate it on the backend, so the generated code is just if(false).
[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!Announcements: New Year, New You?
During the holiday season, we got some of your holiday WTFs. For the next few weeks, we'd love to see your New Year's Resolutions. Maybe ones for you- what WTF do you do that you want to stop doing? But mostly, we're looking for the resolutions you want to give other people- the teammate who microwaves salmon for lunch everyday (it's healthy protein bro), the pointy-haired-boss who thinks they can code because ChatGPT generates code, the company that thinks CI is too much of an expense. What in your day or workplace needs to take on a resolution for this year?
Click submit and let us know!
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!CodeSOD: The Utils
We know 2026 is not a leap year. But how do we know that? We need to call some function to find out.
Steve sends us a bit of representative code; on it's own, it's not so bad, but with the broader context, it's horrifying:
namespace Utils{ public static class Utils { public static bool IsLeapYear(int year) { return CultureInfo.CurrentCulture.Calendar.IsLeapYear(year); } … } }CultureInfo.CurrentCulture.Calendar.IsLeapYear is a .Net built in function. It does what you think. This code wraps it in their own IsLeapYear function, in a class called Utils, in a namespace called Utils.
I think you can see where this is going: Utils.Utils is a "god" class that has all the random utility functions you might want in it. It basically wraps the .Net core library up in its own interface. Sure, it's only the parts that the application needs to use, but it's still a lot of useless code that just piles a big old heap of functions that could mostly be one-liners already in a big bucket.
And of course, not everyone follows this convention, which means that much of the code uses the core library directly, and much of it uses the Utils.Utils. The mixture creates a maintainability nightmare, and it shows: the application has an ever growing bug list.
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.Error'd: Two-faced
For the first Error'd of the future-facing year, we return to our most-hated pattern of every prior year. Namely, broken password mechanisms. Meanwhile, on a personal note, I'm sitting at a boarding gate behind a planeload of people who were scheduled on a flight 12 hours ago! Sure, first-world problems but hoo boy.
"I'll get on that right away" snapped longtime contributor Argle Bargle. "I needed to make a helpdesk request. For some reason they think I need to update my password. Sure, I can appreciate that it's been a while since I've made any password change. The only catch is, I've only been with the company six months."
An anonymous reader griped "When I tried to log into AliExpress by clicking on the sign in button, it gave me the registration form even though an account already exists under the supplied email address. The only way to sign in is to click back and then try again or switch to the mobile view."
Rolf B. reported "Well, I don't even want an account. I only want to download the "VMware Virtual Disk Development Kit" to attempt a repair of my broken vmdk. But the download button now requires to be logged in. Btw: If you attempt to use an email with a '+' in it, the form completely crashes on the first keypress in the password field."
"You can have too much security!" declares Karun R.
And another anonymous (ok, this one came from inside the house but shhh I won't say who) "They said "at least one special character" and provided a list. I gave them TWENTY-FOUR and still that wasn't good enough."
[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.
Best of…: Best of 2025: The Modern Job Hunt
Ellis knew she needed a walk after she hurried off of Zoom at the end of the meeting to avoid sobbing in front of the group.
She'd just been attending a free online seminar regarding safe job hunting on the Internet. Having been searching since the end of January, Ellis had already picked up plenty of first-hand experience with the modern job market, one rejection at a time. She thought she'd attend the seminar just to see if there were any additional things she wasn't aware of. The seminar had gone well, good information presented in a clear and engaging way. But by the end of it, Ellis was feeling bleak. Goodness gracious, she'd already been slogging through months of this. Hundreds of job applications with nothing to show for it. All of the scams out there, all of the bad actors preying on people desperate for their and their loved ones' survival!
Ellis' childhood had been plagued with anxiety and depression. It was only as an adult that she'd learned any tricks for coping with them. These tricks had helped her avoid spiraling into full-on depression for the past several years. One such trick was to stop and notice whenever those first feelings hit. Recognize them, feel them, and then respond constructively.
First, a walk. Going out where there were trees and sunshine: Ellis considered this "garbage collection" for her brain. So she stepped out the front door and started down a tree-lined path near her house, holding on to that bleak feeling. She was well aware that if she didn't address it, it would take root and grow into hopelessness, self-loathing, fear of the future. It would paralyze her, leave her curled up on the couch doing nothing. And it would all happen without any words issuing from her inner voice. That was the most insidious thing. It happened way down deep in a place where there were no words at all.
Once she returned home, Ellis forced herself to sit down with a notebook and pencil and think very hard about what was bothering her. She wrote down each sentiment:
- This job search is a hopeless, unending slog!
- No one wants to hire me. There must be something wrong with me!
- This is the most brutal job search environment I've ever dealt with. There are new scams every day. Then add AI to every aspect until I want to vomit.
This was the first step of a reframing technique she'd just read about in the book Right Kind of Wrong by Amy Edmonson. With the words out, it was possible to look at each statement and determine whether it was rational or irrational, constructive or harmful. Each statement could be replaced with something better.
Ellis proceeded step by step through the list.
- Yes, this will end. Everything ends.
- There's nothing wrong with me. Most businesses are swamped with applications. There's a good chance mine aren't even being looked at before they're being auto-rejected. Remember the growth mindset you learned from Carol Dweck. Each application and interview is giving me experience and making me a better candidate.
- This job market is a novel context that changes every day. That means failure is not only inevitable, it's the only way forward.
Ellis realized that her job hunt was very much like a search algorithm trying to find a path through a maze. When the algorithm encountered a dead end, did it deserve blame? Was it an occasion for shame, embarrassment, and despair? Of course not. Simply backtrack and keep going with the knowledge gained.
Yes, there was truth to the fact that this was the toughest job market Ellis had ever experienced. Therefore, taking a note from Viktor Frankl, she spent a moment reimagining the struggle in a way that made it meaningful to her. Ellis began viewing her job hunt in this dangerous market, her gradual accumulation of survival information, as an act of resistance against it. She now hoped to write all about her experience once she was on the other side, in case her advice might help even one other person in her situation save time and frustration.
While unemployed, she also had the opportunity to employ the search algorithm against entirely new mazes. Could Ellis expand her freelance writing into a sustainable gig, for instance? That would mean exploring all the different ways to be a freelance writer, something Ellis was now curious and excited to explore.
[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.Best of…: Best of 2025: The C-Level Ticket
Everyone's got workplace woes. The clueless manager; the disruptive coworker; the cube walls that loom ever higher as the years pass, trapping whatever's left of your soul.
But sometimes, Satan really leaves his mark on a joint. I worked Tech Support there. This is my story. Who am I? Just call me Anonymous.
It starts at the top. A call came in from Lawrence Gibbs, the CEO himself, telling us that a conference room printer was, quote, "leaking." He didn't explain it, he just hung up. The boss ordered me out immediately, told me to step on it. I ignored the elevator, racing up the staircase floor after floor until I reached the dizzying summit of C-Town.
There's less oxygen up there, I'm sure of it. My lungs ached and my head spun as I struggled to catch my breath. The fancy tile and high ceilings made a workaday schmuck like me feel daunted, unwelcome. All the same, I gathered myself and pushed on, if only to learn what on earth "leaking" meant in relation to a printer.
I followed the signs on the wall to the specified conference room. In there, the thermostat had been kicked down into the negatives. The cold cut through every layer of mandated business attire, straight to bone. The scene was thick with milling bystanders who hugged themselves and traded the occasional nervous glance. Gibbs was nowhere to be found.
Remembering my duty, I summoned my nerve. "Tech Support. Where's the printer?" I asked.
Several pointing fingers showed me the way. The large printer/scanner was situated against the far wall, flanking an even more enormous conference table. Upon rounding the table, I was greeted with a grim sight: dozens of sheets of paper strewn about the floor like blood spatter. Everyone was keeping their distance; no one paid me any mind as I knelt to gather the pages. There were 30 in all. Each one was blank on one side, and sported some kind of large, blotchy ring on the other. Lord knew I drank enough java to recognize a coffee mug stain when I saw one, but these weren't actual stains. They were printouts of stains.
The printer was plugged in. No sign of foul play. As I knelt there, unseen and unheeded, I clutched the ruined papers to my chest. Someone had wasted a tree and a good bit of toner, and for what? How'd it go down? Surely Gibbs knew more than he'd let on. The thought of seeking him out, demanding answers, set my heart to pounding. It was no good, I knew. He'd play coy all day and hand me my pink slip if I pushed too hard. As much as I wanted the truth, I had a stack of unpaid bills at home almost as thick as the one in my arms. I had to come up with something else.
There had to be witnesses among the bystanders. I stood up and glanced among them, seeking out any who would return eye contact. There: a woman who looked every bit as polished as everyone else. But for once, I got the feeling that what lay beneath the facade wasn't rotten.
With my eyes, I pleaded for answers.
Not here, her gaze pleaded back.
I was getting somewhere, I just had to arrange for some privacy. I hurried around the table again and weaved through bystanders toward the exit, hoping to beat it out of that icebox unnoticed. When I reached the threshold, I spotted Gibbs charging up the corridor, smoldering with entitlement. "Where the hell is Tech Support?!"
I froze a good distance away from the oncoming executive, whose voice I recognized from a thousand corporate presentations. Instead of putting me to sleep this time, it jolted down my spine like lightning. I had to think fast, or I was gonna lose my lead, if not my life.
"I'm right here, sir!" I said. "Be right back! I, uh, just need to find a folder for these papers."
"I've got one in my office."
A woman's voice issued calmly only a few feet behind me. I spun around, and it was her, all right, her demeanor as cool as our surroundings. She nodded my way. "Follow me."
My spirits soared. At that moment, I would've followed her into hell. Turning around, I had the pleasure of seeing Gibbs stop short with a glare of contempt. Then he waved us out of his sight.
Once we were out in the corridor, she took the lead, guiding me through the halls as I marveled at my luck. Eventually, she used her key card on one of the massive oak doors, and in we went.
You could've fit my entire apartment into that office. The place was spotless. Mini-fridge, espresso machine, even couches: none of it looked used. There were a couple of cardboard boxes piled up near her desk, which sat in front of a massive floor-to-ceiling window admitting ample sunlight.
She motioned toward one of the couches, inviting me to sit. I shook my head in reply. I was dying for a cigarette by that point, but I didn't dare light up within this sanctuary. Not sure what to expect next, I played it cautious, hovering close to the exit. "Thanks for the help back there, ma'am."
"Don't mention it." She walked back to her desk, opened up a drawer, and pulled out a brand-new manila folder. Then she returned to conversational distance and proffered it my way. "You're from Tech Support?"
There was pure curiosity in her voice, no disparagement, which was encouraging. I accepted the folder and stuffed the ruined pages inside. "That's right, ma'am."
She shook her head. "Please call me Leila. I started a few weeks ago. I'm the new head of HR."
Human Resources. That acronym, which usually put me on edge, somehow failed to raise my hackles. I'd have to keep vigilant, of course, but so far she seemed surprisingly OK. "Welcome aboard, Leila. I wish we were meeting in better circumstances." Duty beckoned. I hefted the folder. "Printers don't just leak."
"No." Leila glanced askance, grave.
"Tell me what you saw."
"Well ..." She shrugged helplessly. "Whenever Mr. Gibbs gets excited during a meeting, he tends to lean against the printer and rest his coffee mug on top of it. Today, he must've hit the Scan button with his elbow. I saw the scanner go off. It was so bright ..." She trailed off with a pained glance downward.
"I know this is hard," I told her when the silence stretched too long. "Please, continue."
Leila summoned her mettle. "After he leaned on the controls, those pages spilled out of the printer. And then ... then somehow, I have no idea, I swear! Somehow, all those pages were also emailed to me, Mr. Gibbs' assistant, and the entire board of directors!"
The shock hit me first. My eyes went wide and my jaw fell. But then I reminded myself, I'd seen just as crazy and worse as the result of a cat jumping on a keyboard. A feline doesn't know any better. A top-level executive, on the other hand, should know better.
"Sounds to me like the printer's just fine," I spoke with conviction. "What we have here is a CEO who thinks it's OK to treat an expensive piece of office equipment like his own personal fainting couch."
"It's terrible!" Leila's gaze burned with purpose. "I promise, I'll do everything I possibly can to make sure something like this never happens again!"
I smiled a gallows smile. "Not sure what anyone can do to fix this joint, but the offer's appreciated. Thanks again for your help."
Now that I'd seen this glimpse of better things, I selfishly wanted to linger. But it was high time I got outta there. I didn't wanna make her late for some meeting or waste her time. I backed up toward the door on feet that were reluctant to move.
Leila watched me with a look of concern. "Mr. Gibbs was the one who called Tech Support. I can't close your ticket for you; you'll have to get him to do it. What are you going to do?"
She cared. That made leaving even harder. "I dunno yet. I'll think of something."
I turned around, opened the massive door, and put myself on the other side of it in a hurry, using wall signs to backtrack to the conference room. Would our paths ever cross again? Unlikely. Someone like her was sure to get fired, or quit out of frustration, or get corrupted over time.
It was too painful to think about, so I forced myself to focus on the folder of wasted pages in my arms instead. It felt like a mile-long rap sheet. I was dealing with an alleged leader who went so far as to blame the material world around him rather than accept personal responsibility. I'd have to appeal to one or more of the things he actually cared about: himself, his bottom line, his sense of power.
By the time I returned to the conference room to face the CEO, I knew what to tell him. "You're right, sir, there's something very wrong with this printer. We're gonna take it out here and give it a thorough work-up."
That was how I was able to get the printer out of that conference room for good. Once it underwent "inspection" and "testing," it received a new home in a previously unused closet. Whenever Gibbs got to jawing in future meetings, all he could do was lean against the wall. Ticket closed.
Gibbs remained at the top, doing accursed things that trickled down to the roots of his accursed company. But at least from then on, every onboarding slideshow included a photo of one of the coffee ring printouts, with the title Respect the Equipment.
Thanks, Leila. I can live with that.
[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.Best of…: Best of 2025: The Sales Target
The end of the quarter was approaching, and dark clouds were gathering in the C-suite. While they were trying to be tight lipped about it, the scuttlebutt was flowing freely. Initech had missed major sales targets, and not just by a few percentage points, but by an order of magnitude.
Heads were going to roll.
Except there was a problem: the master report that had kicked off this tizzy didn't seem to align with the department specific reports. For the C-suite, it was that report that was the document of record; they had been using it for years, and had great confidence in it. But something was wrong.
Enter Jeff. Jeff had been hired to migrate their reports to a new system, and while this particular report had not yet been migrated, Jeff at least had familiarity, and was capable of answering the question: "what was going on?" Were the sales really that far off, and was everyone going to lose their jobs? Or could it possibly be that this ancient and well used report might be wrong?
The core of the query was basically a series of subqueries. Each subquery followed this basic pattern:
SELECT SUM(complex_subquery_A) as subtotal FROM complex_subquery_BNone of this was particularly readable, mind you, and it took some digging just to get the shape of the individual queries understood. But none of the individual queries were the problem; it was the way they got stitched together:
SELECT SUM(subtotal) FROM (SELECT SUM(complex_subquery_A) as subtotal FROM complex_subquery_B UNION SELECT SUM(complex_subquery_C) as subtotal FROM complex_subquery_D UNION SELECT SUM(complex_subquery_E) as subtotal FROM complex_subquery_F);The full query was filled with a longer chain of unions, but it was easy to understand what went wrong, and demonstrate it to management.
The UNION operator does a set union- which means if there are any duplicate values, only one gets included in the output. So if "Department A" and "Department C" both have $1M in sales for the quarter, the total will just be $1M- not the expected $2M.
The correct version of the query would use UNION ALL, which preserves duplicates.
What stunned Jeff was that this report was old enough to be basically an antique, and this was the kind of business that would burn an entire forest down to find out why a single invoice was off by $0.15. It was sheer luck that this hadn't caused an explosion before- or maybe in the past it had, and someone had just written it off as a "minor glitch"?
Unfortunately for Jeff, because the report was so important it required a huge number of approvals before the "UNION ALL" change could be deployed, which meant he was called upon to manually run a "test" version of the report containing the fix every time a C-suite executive wanted one, until the end of the following quarter, when he could finally integrate the fix.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!