Dilbert





The Daily WTF

Error'd: Text Should Go Here;

"The fact that Microsoft values my PC's health over copyediting is why I thumbed up this window," Eric wrote.

 

"Great! Thanks Steam! How am I going to contact Paypal now?"

 

"Now serving order number Not a Number. A totally normal order number, don't question it," Pierre-Luc wrote.

 

"Sure, I had a pretty rough start getting my cheapo smart power outlet up and running, but hey, on the plus side it does look like 2 indeed got changed to 'two'" writes Bob.

 

Andy writes, "I'm not sure how much processing Dreamhost needs to do when making a password with the complexity of YXmztnS5vxA6, but this screenshot was taken after 45 seconds of loading."

 

"I depend heavily on Microsoft Null, but I can't really imagine what kind of updates it might require," Matthew F. wrote.

 

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!


CodeSOD: Switch Off;

There are certain things which you see in code that, at first glance, if you haven’t already learned better, look like they might almost be clever. One of those in any construct that starts with:

switch(true) {…}

It seems tempting at various points. Your cases can be boolean conditions now, but you can also collapse cases together, getting tricky with breaks to build complex logic. It’s more compact than a chain of ifs. It’s also almost always the wrong thing to do.

Kasha stumbled across this while tracking down a bug:

    // The variable names in this code have been anonymized to protect the guilty. In the original they were actually ok.
    private function foo($a, $b)
    {
        switch (true){
            case ($a&&$b): return 'b';
                break;
            case (!$a&&!$b): return 'c';
                break;
            case $a: return 'a';
                break;
            casedefault: return 'unknown';
                break;
        }
    }

As Kasha’s comment tells us, we won’t judge by the variable names in use here. Even so, the awkward switch also contains awkward logic, and seems designed for unreadability. It’s not the most challenging logic to trace. Even Kasha writes “I comprehended the piece just fine at first while looking at it, and only later it hit me how awkward it is.” And that’s the real issue: it’s awkward. It’s not eye-bleedingly bad. It’s not cringe-worthy. It’s just the sort of thing that you see in your codebase and grumble about each time you see it.

And that’s the real WTF in this case. The developer responsible for the code produces a lot of this kind of code. They never use an if if they can compact it into a switch. They favor while(true) with breaks over sensible while loops.

And in this case, they left a crunch-induced typo which created the bug: casedefault is not part of the PHP switch syntax. Like most languages with a switch, the last condition should simply be default:.

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!


Y2K15;

We’re still in the early part of the year, and as little glitches show up from “sliding window” fixes to the Y2K bug, we’re seeing more and more little stories of other date rollover weirdness in our inbox.

Like, for example, the Y2K15 bug, which Encore got to get surprised with. It feels like date issues are turning into a sports game franchise: new releases of the same thing every year.

A long, long time ago, Encore’s company released a piece of industrial machinery with an embedded controller. It was so long ago and so embedded that things like floating point operations were a little to newfangled and expensive to execute, and memory was at an extreme premium.

The engineer who originally designed the device had a clever solution to storing dates. One byte of EEPROM could be dedicated to storing the last two digits of the year. In RAM, a nibble- 4 bits- would then store an offset relative to that base year.

Yes, this had Y2K issues, but that wasn’t really a concern at the time. It also had a rollover issue every 16 years. That also wasn’t really a concern, because it was attached to a giant machine which needed annual service to keep functioning properly. Every few years, the service tech could bring an EEPROM progammer device and flash the base year value in the EEPROM. And if someone missed 16 years worth of service calls, they probably had other problems.

Time passed. Some customers did miss 16 years of service calls. Over time, new features got added. The control interface got an improved LCD. Bluetooth got attached. The networking stack changed. A reporting database got bundled with the product, so all the data being produced by the device could get aggregated and reported on. The way the software interacted with the hardware changed, and it meant that the hardware ran at a lower temperature and could go longer between service calls. But at its core, the chip and the software didn’t change all that much.

In that time, there were also changeovers in the engineering team. People left the company, new engineers joined, documentation languished, never getting updated. Years might pass without anybody touching the software, then suddenly a flurry of customer requests that needed patched RIGHT NOW would come through, and anybody who vaguely understood the software got roped in to do the work, then shunted back off to other projects.

On New Year’s Day, 2016, a deluge of tickets started coming in. Encore, as the last person to have touched the software, started picking them up. They all expressed the same problem: the date had rolled over to 2000. The reporting database was confused, the users were confused, and even if they tried to set the clock to 2016 manually, it would roll back from 2015 to 2000.

Now, no one at the company, including Encore, actually knew about the date system in use at this point. The support manual did say that rollovers meant the device had gone 16 years without being properly serviced, but some of these customers had brand new devices, less than a year old. And customers with devices older than 16 years weren’t seeing this problem.

Encore investigated, and picked apart how the date handling worked. That, itself, wasn’t the problem. It took a lot more investigation to track down the problem, including going back to the board schematics to trace how various hardware components were connected. After a few hair-on-fire weeks of crisis management, Encore pieced together the series of events as they were best able.

Sometime after the year 2000, Bluetooth was added to the device. Something about how the Bluetooth module connected to the other components had broken the flasher-software that could update the base year. This meant that the devices had never had their base year set, and simply had a 0 value- 0x00, or the year 2000.

Which meant, for the next 16 years, everything was fine. Techs went out, tried to flash the EEPROM, reset the clock to the correct date, and went about their business, never aware that they hadn’t actually done anything. But come 2016, all of these devices rolled back over to the year 2000.

Encore was able to figure out a script to trick the system into adjusting the output to correct the base year issue, but it also meant many customers had database crammed with bad data that needed to be adjusted to correct the erroneous year.

After this, Encore’s company released upgraded version of the system which contained a GPS receiver, so that it could set its date based on that, but a large number of their customers weren’t interested in the upgrade. Encore has already blocked off the first few weeks of 2032 in preparation.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!


Representative Line: Gormless and Gone;

There’s always a hope that in the future, our code will be better. Eventually, we won’t be dealing with piles of krufty legacy code and unprepared programmers and business users who don’t understand how clicking works. It’s 2020: we officially live in the future. Things aren’t better.

Duane works in Go, and has a piping hot “Representative Line” written in 2020. If, like me, you don’t quite know Go, it still looks pretty terrible at first glance:

db.Raw("update backlog set id = ? where id = ?;", job_id, job_id).Row()

The SQL query is… a head scratcher, for sure. id is the primary key in this case, and as a general rule, updating the primary key in a relational database is not a good idea: it is the identity of the record, and if it’s used in relationships you can have weird cascading failures. But it’s okay in this case, since we’re setting the id equal to job_id where id already equals job_id, which gives us a nice NOP.

Theoretically, this might cause some triggers to fire, but that’s it’s own WTF.

There are other problems here, if you know a little bit about Go. First, db is a “GORM” object- Go’s ORM layer. If you just want to update a single object, using the ORM layer directly is probably cleaner and more readable. But if you do want to execute raw SQL that returns no results, like an update, the correct method to use is Exec, not Raw. Raw + Row is used when you intend to capture the results.

Duane adds: “The return result from Row() isn’t assigned to a variable. So this line ignores any output that Row() might have had, including any errors.”

Duane also adds: “This particular programmer is no longer working for us for some reason.”

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!


CodeSOD: An Unreal Json Parser;

As we've discussed in the past, video game code probably shouldn't be held to the standards of your average WTF: they're operating under wildly different constraints. So, for example, when a popular indie game open sources itself, and people find all sorts of horrors in the codebase: hey, the game shipped and made money. This isn't life or death stuff.

It's a little different when you're building the engine. You're not just hacking together whatever you need to make your product work, but putting together a reusable platform to make other people's products work.

Rich D, who previously shared some horrors he found in the Unreal engine, recently discovered that UnrealScript has a useful sounding JsonObject. Since Rich is thinking in terms of mods, being able to read/write JSON to handle mod configuration is useful, but anyone designing a game might have many good reasons to want JSON documents.

The file starts promisingly with:

class JsonObject extends Object native; /// COMMENT!! …

It's good that someone put that comment there, because I assume it was meant as a reminder: comment this code. And the comments start giving us hints of some weird things:

/** * Looks up a value with the given key in the ObjectMap. If it was a number * in the Json string, this will be prepended with \# (see below helpers) * * @param Key The key to search for * * @return A string value */ native function string GetStringValue(const string Key);

The method GetStringValue returns a string from JSON, but if the string is a number, it… puts a \# in front of it? Why?

function int GetIntValue(const string Key) { local string Value; // look up the key, and skip the \# Value = Mid(GetStringValue(Key), 2); return int(Value); }

Oh… that's why. So that we can ignore it. There's a similar version of this method for GetFloatValue, and GetBoolValue.

So, how do those \#s get prepended? Well, as it turns out, there are also set methods:

function SetIntValue(const string Key, int Value) { SetStringValue(Key, "\\#" $ Value); }

In addition to these methods, there are also native methods (e.g., methods which bind to native code, and thus don't have an UnrealScript body) to encode/decode JSON:

/** * Encodes an object hierarchy to a string suitable for sending over the web * * @param Root The toplevel object in the hierarchy * * @return A well-formatted Json string */ static native function string EncodeJson(JsonObject Root); /** * Decodes a Json string into an object hierarchy (all needed objects will be created) * * @param Str A Json string (probably received from the web) * * @return The root object of the resulting hierarchy */ static native function JsonObject DecodeJson(const string Str);

Guided by this code, Rich went on to do a few tests:

Rich has wisely decided not to leverage this object, for now.

[Advertisement] Ensure your software is built only once and then deployed consistently across environments, by packaging your applications and components. Learn how today!


Error'd: Are You Old Enough to Know Better?;

"I guess my kid cousins won't be putting these together for a while," Travis writes.

 

Noah writes, "Who doesn't want a little error in their coffee first thing in the morning?"

 

"It would appear that Walmart and I have very different ideas about what constitutes 'Hard Candy'," wrote Todd P.

 

"Looks like the push to build roads in Poland paid off! Like, really REALLY paid off," Krzysztof wrote.

 

"Google nailed it - it caught all the cities that I visited in the um...Pacific region?" Francois wrote.

 

Darnell S. writes, "I beg to differ with WizzAir Cars' opinion of what is a 'good choice'...I want that free one!"

 

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!


The Compliance Ropeway;

"So, let me get this straight," Derrick said. He closed his eyes and took a deep breath while massaging his temples before letting out an exasperated sigh. "Not a single person... in this entire organization... is taking ANY responsibility for Ropeway? No one is even willing to admit that they know anything about this application...?"

The Operations team had grown accustomed to their new director's mannerisms and learned it's just better to stay silent and let Derrick think out loud. Afterall, no one envied his job or his idealistic quest for actual compliance. If had he been at the bank as long as his team had, Derrick would have learned that there's compliance... and then there's "compliance."

"But we figured out that Ropeway somehow automatically transfers underwriting overrides from ISAC to AppPortal?" Derrick paused to collect his thoughts before a lightbulb went off. "Wait, wait. Those systems are both covered under our IBM Master Service Agreement, right? What did they say? Chris... did you reach out to our IBM liaison?"

"Well," Chris silently thanked everything good that Ropeway wasn't his problem. "IBM says that they have no idea. They said it's not in the scope of the MSA or any SOW, but they'd be happy to come out and—"

"Ab-so-lute-ly not," Derrick interrupted. He wasn't IBM's biggest fan, to put it mildly. "I've already eaten into next year's budget on this SSL initiative, and there's no way I'm gonna pay them just to tell me I have to pay them even more to fix what shouldn't even by my problem!"

Derrick let out another sigh, rubbing his temples again. "All I want," he grimaced, "is for Ropeway to use HTTPS instead of HTTP. That's all! Fine... fine! Chris, let's just move the whole damn Ropeway server behind the proxy."

"Roger that," Chris nodded, "We'll start prepping things for next week's maintenance window."

There was a lot of risk to moving Ropeway. The Operations team knew how to keep it running – it was just a Windows Service application – but they had no way of knowing if the slightest change in the environment would break things. Moving the server behind the http-to-https proxy meant a new IP and a new subnet, and they had seen far too may "if (IP==10.10.22.30) production_env = true" traps to know they can't just move things without a test plan.

But since no one on the business or Development side was willing to help, they were on their own and it'd be Derrick's head if ISAC or AppPortal stopped working once that maintenance window was over. But for the sake of actual compliance – not "compliance" – these were the risks Derrick was willing to take: SSL was simply non-negotiable.

##

"You'll never believe what I found on that Ropeway server," Chris said while popping into to Derrick's office. Actually, he knew that wasn't true; Derrick had come to expect the unbelievable, but Chris liked to prep Derrick nonetheless. Derrick took a deep breath and moved his hand towards his forehead.

"I found this." Chris plopped down a thick, tattered manila envelope that was covered in yellowed tape. "It was... um... taped to the server's chassis."

Derrick was legitimately surprised and started riffling through the contents as Chris explained things. "So apparently Ropeway was built by this guy, Jody Dorchester, at Roman, uh, wait. Ronin Software or something."

"And yeah," Chris continued as Derrick's eyes widened while he flipped through page-after-page-after page of documentation, "Jody apparently wrote all sorts of documentation... installation instructions, configuration instructions – and all the source code is on that enclosed CD-ROM."

Derrick was speechless. "This," he stuttered, "is dated... March ...of 2000."

"Yup," Chris jumped in nonchalantly, "but I took a shot in the dark here and sent Jody an email."

"And...," Chris said, smiling. He handed Derrick another document and said, "here's his reply."

Ropeway! Wow... that takes me back. I can't believe that's still around, and if you're contacting me about it... you must be desperate ;)

I built that app in a past life... I don't know how much this will help, but I'll tell you what I remember.

There was a fellow at the bank, Eric (or maybe Edward?), and he was a Director of Technology and a VP of something. I met him at a local networking event, and he told me about some project he was working on that was going to reduce all sorts of mindless paperwork.

One department over there was apparently printing out a bunch of records from their system and then faxing all that paper to a different department, who would then manually re-enter all those records into a different system. They had a bunch of data entry people, but the bigger problem was that it was slow, and there were a lot of mistakes, and it was costing a lot of money.

It sounded like a huge, complicated automation project – but actually, your guy had it mostly figured out. The one system could spit-out CSV files to some network share, and the other could import XML files via some web interface. He asked if I could help with that, and I said sure... why not? It just seemed like a really simple Windows service application.

It took a bit longer to wrangle those two formats together than I hoped, but I showed it off and he seemed absolutely thrilled. However, I'll never forget the look on his face when I told him the cost. It was something like 16 hours at $50/hr (my rate back then). I thought he was upset that I took so long, and billed $800 for something that seemed so simple.

Not even close. He said that IBM quoted over $100k to do the exact same thing – but there was just no way he could sell that he got this massive integration project accomplished for only $800. He said I needed to bill more... a lot more.

So, I made that little importer app as robust and configurable as what, VB4 would allow? Then I spent, like, a week writing that documentation you guys found, taped to the server. You know, I actually bought that server and did all the installation myself? Well after all that, he was satisfied with my new bill.

Anyways, I can't remember anything about the application, but there's probably a whole section of the docs dedicated to configuring it. Hopefully you guys can figure it out... good luck!

Jody was right. On page 16, there was, in fact, a section dedicated to the Web API configuration. To change use SSL, one would just have to open the service control tool, check off the "use secure connection," and then Ropeway would construct the Service URL using HTTPS instead of HTTP. That was it, apparently.

"I just... I can't believe it," Derrick paused, and shook his head before massaging his forehead – this time more in surprise that his usual temple massage. "No way. It can't be that simple. Nothing here is that simple!"

Chris shrugged his shoulders and said, "Checking that box does seem a bit simpler than moving—"

"Look," Derrick interrupted, "even if we change the setting, and that setting works, someone needs to own Ropeway, and take responsibility for it going forward. This is like rule number one of actual compliance!"

Chris nodded, and just let Derrick build up to what would certainly be yet another compliance rant.

"Come on," Derrick said enthusiastically, "Ropeway is so absurdly documented... look at this! Surely someone in Core Dev, Biz Apps, Vendor Apps, or heck, even Apps Integration will adopt this thing!? I mean... you realize what will happen if AppPortal craps out because the Ropeway integration breaks some day?"

Obviously, Chris knew exactly how bad it would be, but he let Derrick tell him anyways.

"I can't even imaginae it," Derrick took a breath. "The crap storm that all of those groups would face... this might even make the shareholder meeting! We gotta do something. How about we go to the ISAC team lead and say... here's Ropeway. It's your baby now. Congrats! Here's the docs, it's really easy to use, just--"

"Look," Chris cut in, soberly. "If you want me to go deliver that message -- in the middle of their whole Agile ScrumOps whatever war with Biz Apps – I will. But I'm pretty sure they're gonna go straight to the execs and push to expand the MSA with IBM to cover the App Portal integration..."

Chris paused for a few moments to let Derrick realize exactly who's budget an MSA expansion might come from. Derrick's eyes widened as he took another deep breath.

"Oooor", Chris continued, "this envelope still, umm, has a quite a bit of tape attached to it. Maybe... just maaaaybe...we never found the envelope in the first place? And perhaps, I don't know, Ropeway just... uhhh... happens to check that box itself one day? I don't know? It's an old app... old apps do weird things. Who knows? I don't... do you? Wait... I've already forgotten, what's Ropeway?"

Derrick slowly shook his head and started massaging the bridge of his nose with his index fingers. He let out a completely different sigh, defeated sigh, then uncharacteristically mumbled, "...better get some more tape..."

[Advertisement] Ensure your software is built only once and then deployed consistently across environments, by packaging your applications and components. Learn how today!