Last minute geek

last minute tech news from around the net

Tuesday, Dec 18th

Last update11:12:00 PM

You are here: English WTF

WTF

Keeping Up Appearances

Just because a tool is available doesn't mean people will use it correctly. People have abused booleans, dates, enums, databases, Go-To's, PHP, reinventing the wheel and even Excel to the point that this forum will never run out of material!

Bug and issue trackers are Good Things™. They let you keep track of multiple projects, feature requests, and open and closed problems. They let you classify the issues by severity/urgency. They let you specify which items are going into which release. They even let you track who did the work, as well as all sorts of additional information.

An optical illusion in which two squares that are actually the same color appear to be different colors

Every project, no matter how big or small, should make use of them.

Ideally, they would be used correctly.

Ideally.

Matt had just released the project that he'd been working on for the past few years. As always happens, some "issues" cropped up. Some were genuine defects. Some were sort-of-enhancements based on the fact that a particular input screen was unwieldy and needed to be improved. At least one was a major restructuring of a part of the project that did not flow too well. In all, Matt had seven issues that needed to be addressed. Before he could deliver them, he needed defect tickets in the bug tracking system. He wasn't authorized to raise such tickets; only the Test team could do that.

It took a while, but he finally received a ticket to do the work to... but everything had been bundled up into one ticket. This made it very difficult to work with, because now he couldn't just clear each issue as he went. Instead, he had to package them up in abeyance, so to speak, and only release them when they were all complete. This also meant that the test documentation, providing instructions to the Test team as to how to ensure that the fix was working as required, all had to be bundled up into one big messy document, making it more difficult for Testers to do their job as well.

So he questioned them: If we can raise a single defect ticket, then what stops us from raising all 7 needed tickets so that the issues can be addressed separately? The answer was: Because these defects appear post-release, it is clear that they weren't caught at the pre-release stage, which means that Somebody Wasn't Doing Their Job Properly in the Test team, which makes them Look Bad; it brings their failure to catch the issues to the attention of Management.

In other words, in order to keep the Test team from looking bad, they would only ever raise a single ticket (encompassing all detected issues) for any given release.

Imagine if all of the bugs from your last major release were assigned to you personally, in a single ticket. Good luck estimating, scheduling, coding, debugging and documenting how to test the single logical bug!

Matt raised this bad practice with management, and explained that while the reason for why they do this is to hide their inadequacy, it also prevents any meaningful way to control work distribution, changes and subsequent testing. It also obscures the actual number of issues (Why is it taking you seven weeks to fix one issue?).

Management was not amused at having been misled.

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

Read all

CodeSOD: Rectangle Marks The Spot

World Map flat Mercator

If you need your user's country of origin, there are many ways you can go about obtaining it programmatically. Some may opt for a simple drop-down that prompts the user to specify his/her country. If you don't want to burden your user this way, you might look at their session data and return their country of origin, time zone, or some other useful information. If you have fancy enough APIs at your disposal, you could even reverse geocode the user's longitude/latitude position and obtain an address.

Or, you can start with their location and perform the code equivalent of throwing a dart at a map littered with creepy-looking post-it notes:

def country(latitude, longitude):
  if -130 < longitude < -60:
    return 'US'
  elif 110 < longitude < 155 and -40 < latitude < -10:
    return 'AU'
  elif -8 < longitude < 2 and 50 < latitude < 60:
    return 'GB'
  elif 60 < longitude < 100:
    return 'IN'
  return None

def timezone(longitude):
  return int(longitude * 0.0655737704918)

Submitter Zekka writes: "When we decided to internationalize our app, it became necessary to determine what country the user was in. That's not even the correct constant to convert longitude to approximate timezone. I have no clue where they got it. It should be 0.06666 ..."

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

Read all

CodeSOD: Look Ahead. Look Out!

I'm an old person. It's the sort of thing that happens when you aren't looking. All the kids these days are writing Slack and Discord bots in JavaScript, and I remember writing my first chatbots in Perl and hooking them into IRC. Fortunately, all the WTFs in my Perl chatbots have been lost to time.

"P" has a peer who wants to scrape all the image URLs out of a Discord chat channel. Those URLs will be fetched, then passed through an image processing pipeline to organize and catalog frequently used images, regardless of their origin.

Our intrepid scraper, however, doesn't want to run the risk of trying to request a URL that might be invalid. So they need a way to accurately validate every URL.

Now, the trick to URLs, and URIs in general, is that they have a grammar that seems simple but is deceptively complex and doesn't lend itself to precise validation via regular expressions. If you were a sane person, you'd generally just ballpark it into the neighborhood and handle exceptions, or maybe copy/paste from StackOverflow and call it a day.

This developer spent 7 hours developing their own regular expression to validate a URL. They tested it with every URL they could think of, and it passed with 100% accuracy, which sounds like the kind of robust testing we'd expect from the person who wrote this:

const regex = /((?:(http|https|Http|Https|rtsp|Rtsp)://(?:(?: [a-zA-Z0-9$-_.+!*'(),;?&=]|(?:%[a-fA-F0-9]{2})){1,64}(?:: (?:[a-zA-Z0-9$-_.+!*'(),;?&=]|(?:%[a-fA-F0-9]{2})){1,25})? @)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9-]{0,64}.)+(?:(?:aero|arpa|asia|a [cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c [acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g [abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop] )|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz]) |(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r [eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u [agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1] [0-9]{2}|[1-9][0-9]|[1-9]).(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9] |[1-9]|0).(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0).(?:25 [0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?::d{1,5})?)(/(?:(?: [a-zA-Z0-9;/?:@&=#~-.+!*'(),_])|(?:%[a-fA-F0-9]{2}))*)? (?:b|$)/gi

Note each use of (?:). These are "look ahead" matches, which will execute depending on what comes after them. Using one or two of these in a regex makes its massively more complicated. This regex uses 32 look ahead expressions, taking "unreadability" to a new height, and flirting with the lesser demons which serve Zalgo. Bonus points for making the comparison case insensitive, but also checking for both http and Http, just in case.

"There's no module on NPM that can do all of this!" the developer proudly proclaimed. They then presumably uploaded it to NPM as a "microframework", used it within a few of their own modules, and then those modules got used by some other modules, and now 75% of the web depends on this regex.

[Advertisement] ProGet can centralize your organization's software applications and components to provide uniform access to developers and servers. Check it out!

Read all

CodeSOD: Assertive Programming

Defensive programming is an important tool in any developer's toolbox. In strictly typed languages, types themselves provide a natural defense against certain classes of bugs, but in loosely typed languages, you may have to be more clear about your assumptions.

For example, in Python, you might choose to use the assert keyword to, well, assert that something is true. It's often used in debugging, but it's also a good way to ensure that the state of the parameters passed to a function, or some other state of your system is correct before doing anything else. If it's not, the code raises an exception.

Dima R found this "interesting" riff on that concept.

try: assert r.status_code == 201 except: print(r.text) pass

Here, the assertion is confirming that we get the expected HTTP status code from a request, but if we didn't, it doesn't bubble up the exception- it just prints the body of the response.

This code has been in production for some time. When Dima tracked down the culprit and asked what they were thinking, the developer admitted:

it was originally an assert just for sanity, but then I wanted to print the result if the assert failed and I wasn't paying very much attention lol

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

Read all

Error'd: Exponential Customer Service

"I think I'm missing some precision in my Dell customer number," writes Steve B.

 

Tief K. wrote, "Looking for culture in Vienna? You might try the theatre for a surprise."

 

"Funny thing happened while reading Raymond Chen's blog https://blogs.msdn.microsoft.com/oldnewthing/20180803-01/ where he referenced a page on Alaskan ferries which then showed me the attached ad," Sam L. writes.

 

Alicia wrote, "Is there anything Amazon doesn't sell?"

 

"I was having Internet connection problems, so decided to relax a bit and play some Diablo 3. Maybe it's a sign that I should go read a book instead," Radek K. writes.

 

Steve L. wrote, "Looks like mini symposium 215 has been updated to discuss the topic of HTML pasting worst practices."

 

[Advertisement] Forget logs. Next time you're struggling to replicate error, crash and performance issues in your apps - Think Raygun! Installs in minutes. Learn more.

Read all

CodeSOD: Extending Yourself

Optional parameters are a great tool for building flexible APIs. In most languages, they're not strictly necessary- if you have function overloading, the difference between optional parameters and an overloaded function is just the quantity of boilerplate- but they're certainly a nice to have.

Well, they're a nice to have in the right hands.

Scattered through their code base, Ian P saw many, many calls to dutData.GetMessages(). As they explored the code base, they used Visual Studio's "go to definition" feature to jump to the implementation- and found they were sometimes ending up in different spots.

public static IEnumerable<string> GetMessages(this ScreenScraper screenScraper) { //Do some stuff to get the messages } //snip 100+ lines public static IEnumerable<string> GetMessages(this ScreenScraper screenScraper, long timeSpane = 30000, int timeInterval = 500) { //Do some different stuff to get the messages }

Frankly, I'm a little surprised that this is even possible. It offered warnings, but no errors, presumably because this is an odd bit of syntactic sugar in C# called "extension methods", which are C#'s answer to "monkey patching". Neither GetMessages is actually a member of ScreenScraper, but if you call GetMessages on a ScreenScraper object, C# will call GetMessages and pass an instance of ScreenScraper into it.

The C# compiler is the real WTF. As for Ian, the fix was simple: rename some methods for clarity, and convert extensions to instance methods as appropriate.

[Advertisement] Forget logs. Next time you're struggling to replicate error, crash and performance issues in your apps - Think Raygun! Installs in minutes. Learn more.

Read all

Representative Line: You Can Only Get What You Have

Sean's ongoing career as a consultant keeps supplying him with amazing code.

Let's talk about encapsulation. We put getters and setters around our objects internalsto help keep our code modular. Given an object, we call something like getUsername to extract a piece of that object safely.

In the same codebase as IsTableEmpty, Sean found this short-but-sweet gem:

public String getUsername(String username) { return username; }

This version of getUsername requires you to already have the username. Oddly, it behaves unpredictably, as if you pass it a postal code, it returns the postal code, and doesn't complain that it isn't a username.

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

Read all