CodeSOD: Get Out Your Decoder Ring |
Back in the late 60s, early 70s, “Fourth Generation Languages” (4GL) seemed like the future. “Write programs without a programmer!” they promised. “It’s a specification-based language, you just tell the computer what should happen, and it figures out how to do it!”
The most famous and probably most widely deployed 4GL, when all its variants and dialects are taken as a single unit, has to be SQL. SQL is the epitome of a specification-based language: each SQL statement represents an expression in relational algebra, and the database gets to use its own internal logic for deciding the best way to execute that statement, making database tuning a dark art involving statistical modeling and a lot of, “I dunno, but when I use this hint it runs fast.”
Speaking of “programs without a programmer”, Nicholas G is trying to update some old SQL queries to a new database engine. That’s where this was found:
DECODE(TRPT.TIERS_DESTINATAIRE_AMONT1,TRPT.TIERS_DEPART_AMONT2,
0,
Decode(TRPT.Tiers_Destinataire_Amont2,TRPT.Tiers_Depart_Amont3,Decode(Tiers_Destinataire_Amt2.Tie_Type_Depot,'PLF',0,
Decode(Tiers_Depart_Amt2.Tie_Depot_Debord, TRPT.Tiers_Destinataire_Amont2,0,Decode(TRPT.Tiers_Destinataire_Amont2,TRPT.Tiers_Depart_Amont3,0,1
))),
DECODE(TRPT.Tiers_Destinataire_Amont3,TRPT.Tiers_Depart_Amont4,
DECODE(TIERS_DEPART_AMT3.TIE_DEPOT_DEBORD, TRPT.TIERS_DESTINATAIRE_AMONT3,
0,
1),
DECODE(Tiers_Depart_Amt1.Tie_Type_Depot,'PLF',
DECODE(Tiers_Destinataire_Amt1.Tie_Type_Depot,'PLF',
0,
Decode(Tiers_Depart_Amt2.Tie_Type_Depot,'PLF',
Decode(Tiers_Destinataire_Amt2.Tie_Type_Depot,'PLF',
0,
Decode(Tiers_Depart_Amt3.Tie_Type_Depot,'PLF',
Decode(Tiers_Destinataire_Amt3.Tie_Type_Depot,'PLF',
0,
1),
1)
),
1)
),
1) )))
I could decode this, but I don’t want to. For those unfamiliar, the SQL DECODE
is SQL’s strange blend of a ternary and a switch. The first argument is your input value. Each successive pair of arguments is the value you wish to compare it to, and the value to return if the input and the compare value are equal. The last parameter is your “default” case. E.g., DECODE(a, 1, "It's one!", 2, "It's two!", "I don't know what it is.")
would return “It’s one!” if a==1
, “It’s two!” if a==2
, and “I don’t know…” in any other case.
Like a ternary, they have their place. Also like a ternary, not like this. Not like this.
Метки: CodeSOD |
CodeSOD: The Map you Pay For |
Soraya’s company recently decided to expand the payment options that they support. This meant integrating “Inipay”, Initech’s API for handling payment processing globally. This particular API is open sourced, which means that Soraya was able to investigate exactly how the sausage was made.
Many of the classes were tagged as being @author auto create
. In fact, there were about 2,000 such classes, all nearly identical aside from a few minor differences. What got Soraya’s attention though was that each of them referred to InipayObject
and InipayHashMap
. Re-implementing standard classes is always a concern.
public class InipayHashMap extends HashMap
That right there is a bit menacing. I’m actually a big fan of aliasing complex generic types into simpler classes, but a HashMap
tells me that we’re looking at stringly typed code.
public String put(String key, Object value) {
String strValue;
if (value == null) {
strValue = null;
} else if (value instanceof String) {
strValue = (String) value;
} else if (value instanceof Integer) {
strValue = ((Integer) value).toString();
} else if (value instanceof Long) {
strValue = ((Long) value).toString();
} else if (value instanceof Float) {
strValue = ((Float) value).toString();
} else if (value instanceof Double) {
strValue = ((Double) value).toString();
} else if (value instanceof Boolean) {
strValue = ((Boolean) value).toString();
} else if (value instanceof Date) {
DateFormat format = new SimpleDateFormat(InipayConstants.DATE_TIME_FORMAT);
format.setTimeZone(TimeZone.getTimeZone(InipayConstants.DATE_TIMEZONE));
strValue = format.format((Date) value);
} else {
strValue = value.toString();
}
return this.put(key, strValue);
}
So, this is how they overload the put
method. Fun fact: if you invoke toString
on a String
object in Java, it returns itself. Which means nearly all of the instanceof
checks are 100% unnecessary. I say nearly, because while you could call Object.toString
on pretty much everything, Date
s do need some special care and handling. Still, I’m skeptical that this code belongs in your HashMap
implementation.
Note, the last line calls the base class’s put
, but… no, not really. We overrode that, too.
public String put(String key, String value) {
if (StringUtils.areNotEmpty(key, value)) {
return super.put(key, value);
} else {
return null;
}
}
The real magic here is that if key
and value
don’t meet whatever criteria areNotEmpty
requires (presumably not null, and not empty strings), we silently ignore them. We don’t fail. We don’t raise an exception. We just silently ignore it. Worse, the put
method in Java’s Map
s should return the old value, if there was one, and null otherwise, so this doesn’t even fit the contract of the interface it’s implementing, and thus doesn’t behave like a HashMap
should.
In practice, these InipayHashMap
objects are used as part of every one of the 2,000 request objects, meant to store “user defined values”. In other words, it’s an uncapped pile of stringly typed data offered to end users to do whatever they please with it, making it maximally Enterprisey.
Метки: CodeSOD |
CodeSOD: ToArray, then REST a bit |
Mandy’s company was brought on to port some REST APIs to Java for a client. Those APIs were written in an in-house, proprietary programming language. Possibly this was a deployment of BobX? Regardless of what the in-house language was, it was everything one would expect from the Inner-Platform Effect. Weird, complicated, tortured logic.
Somewhere in Mandy’s company, a pointy-haired-boss decided they’d throw a junior developer at this. “They did a REST API during their internship, how hard could translating this logic be?” Well, that junior developer didn’t understand the ins-and-outs of Java that well. They certainly didn’t understand the original APIs they were trying to port. The result is that they tried to follow the twisted logic of the in-house language while trying to fumble through Java.
One API method provided a map of countries: {"US": "United States", "DE": "Germany", "CN": "China",…}
. They wanted to map this into objects, in the structure {"label": "US", value: "United States"}
. This was their solution.
private void mapCountries(BackendServiceResponse response, ApiResponse apiResponse) {
Map countries = response.getCountries();
int size = countries.size();
String[] stringArray = new String[size];
String[] keySet = countries.keySet().toArray(stringArray);
String[] values = countries.values().toArray(stringArray);
apiResponse.setCountries(executeMapping(keySet, values));
}
private List executeMapping(String[] keySet, String[] values) {
List countries = new ArrayList();
for(int i = 0; i < keySet.length; i++) {
Country country = new Country();
country.setLabel(keySet[i]);
country.setValue(values[i]);
countries.add(country);
}
return countries;
}
Which gives us this. Note how they take the Map
of countries and split it into the pairs of keys and values, using keySet
and values
. This is where the real problem lurks: there’s no guarantee that the internal implementation of Map
is going to guarantee that ordering. In fact, lots of possible internal implementations absolutely won’t return keySet
and values
in the same order.
These split key/value pairs, which might be in the same order, are then passed off to another method to iterate across them. If, instead, they iterated across the original Map
in the first method, the code would be cleaner, easier to understand, and wouldn’t have the ordering problem. Of course, they could have also used the built-in entrySet
method would would return a collection of sets, where each set was the key/value pair.
Except this code doesn’t have the ordering problem, because it’s not doing what it claims to do. The expectation was that it would return {"label": "DE", "value": "Germany"}
. What it actually returns is {"label": "Germany", "value": "Germany"}
, and that’s down to the toArray
call. toArray()
, with no arguments, returns an Object[]
. toArray(T[])
returns an array of type T, but not just returns an array: it uses that array as its allocation space. From the docs:
Returns an array containing all of the elements in this collection; the runtime type of the returned array is that of the specified array. If the collection fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this collection.
So, stringArray
is passed to collect the keys, and then passed to collect the values, and the end result is that it contains only the values. No one noticed. Either the tests weren’t checking that, or the tests were assuming the incorrect behavior was correct. The end users of the RESTful API didn’t notice the change. Regardless, it was not the behavior of the original API, which- despite being the kind of tortured logic which drives junior developers to drink- managed to stumble into correctly outputing label/value pairs for countries.
Метки: CodeSOD |
Greek To Me |
Many decades ago—before laser printers, graphical operating systems, and device-independent imaging models—Gus worked in the IT department of a local college. As a personal project during slow moments at work, he took it upon himself to figure out how to print Greek text. About a week later, he'd hacked together a solution that resulted in a printout of classical Greek writing.
Gus' boss, although a manager in IT, happened to be a classical scholar. He'd never seen Greek text printed from a normal printer before, and he was ecstatic. He told his friends, who told their friends, and so on. The world of classical Greek scholars soon buzzed with the excitement of a rowdy symposium.
One day, Gus received an email from an unknown professor at an Arizona college. He'd heard from Gus' boss about the wonderful, mythical software. Could he have it, too?
Gus wanted to oblige, but there was a problem. His solution was specific to the previous version of the VAX/VMS operating system and Pascal compiler, to one particular VERSAMOD-200 printer that could be put into a dot-matrix mode, and to a special print driver that'd been carefully binary-patched so that it wouldn't mess up dot-matrix images. Gus doubted the professor had the technical knowledge to appreciate this explanation, so he replied in polite, less technical terms: sorry, but his software just wouldn't work anywhere else.
A week later, his boss showed up at his desk, mentioning the friend in Arizona and nicely asking whether Gus couldn't find some way to send him the software after all. Gus' attempts to explain the impossibility of getting the code running on any other computer in the world fell on deaf ears.
"You're a genius, Gus! I'm sure you'll think of something. Thanks!" Pleased with his own optimism, the boss left.
Gus thought about what he could possibly do to comply, or even semi-comply, with the request. Finally, he hit upon an idea. Into his computer's shell prompt, he typed:
DUMP /HEX "PRINTGREEK.EXE" /LIST=VERSAMOD-200
A hex dump of his program executable soon took tangible form on paper. Gus smilingly collected the printout and walked it over to his boss' office. "Here you go! It's the software, just like you asked."
"Oh!" The boss looked startled, but receptive.
"If they have any trouble installing it, have them get in touch with me and I'll help them out," Gus said.
"All right! Well, thank you!" The boss glanced over his cluttered desk, hunting for a suitable mailing envelope.
Some time later in Arizona, another of our dear IT colleagues no doubt received this hex dump on paper and was told to install it. He or she must have quite the harrowing WTF to tell us—but apparently, it was a successful one. It’s been thirty years since this particular incident, and Gus has never heard back from the professor or anyone at his school. Perhaps someone struck a deal with Hades, or simply let Chronos march forward to a time when printing special characters was no longer such a Sisyphean task.
Метки: Feature Articles |
Error'd: Do You Speak United States? |
Mark wrote, "A Computer Science Degree + a New York certification + ability to speak United States?...I'm the perfict fit!!"
"Especially the more difficult topics in math are always one click away on Smartick, like 'counting to three'," writes Matthias.
"Sorry, iCloud, just becuase you say something is hidden doesn't make it so," Josiah writes.
Todd E. wrote, "110 billion events per bit? That's some pretty lossy compression they've got going on there."
"Someone really needs to have a chat with the folks behind Hertz's 'nearest location' algorithm," writes Brent C.
Michael P. writes, "Save discount_percent%? Sounds like a positive_emotion idea to me!"
Метки: Error'd |
CodeSOD: The Honeypot |
Pitor works for a web development shop. They’ll develop and design sites, usually pretty simple ones, for their customers. They’ll host them. They’ll update them. Every once in awhile, a customer will think “we could do this cheaper in house!” and takes their site and their contract to a cheap webhost.
Sometimes, those customers come back when they realized their mistake.
Thus, when Initech came back, their site was… in a bit of a state. When Pitor’s company handed it off, comments were provided by a Facebook plugin. At some point, someone decided that they wanted to use a Django plugin to keep comments entirely in-house, so they “disabled” the Facebook comments. How?
FB.init({
//appId: '1234567890123456789',
version: 'v2.8',
xfbml: true,
});
They just commented out the app ID, thus preventing the plugin from ever properly initializing. At least, that’s what they did on the desktop version of the page. On the mobile version, the Facebook plugin still loaded, but they broke something else and it just showed random comments.
This change, of course, brought in new problems. Facebook’s ability to filter out spam and bots may not be great, but it’s a step above “nothing at all”. They needed a way to filter out all those bad comments. So they added this HTML to the comment form:
The whitespace was in the original.
No, this item wasn’t set to be invisible. That might have been the intent, at some point, as this StackOverflow question suggests (and presumably, that’s where they stole the idea from). That’s almost-but-not-really clever, as the most naive spambot is likely to try and fill in every field in the form, without checking if they’re visible. Making it actually visible removes even the hint of cleverness, and instead gives the comment form the ambiance of a dirty van with “Free Candy” written on the side.
Метки: CodeSOD |
CodeSOD: Whose Tern is it to Play? |
Every once in awhile, someone sends us some code from a game. Now, I’ve never delved deep into game development, aside from making a 3D asteroids game as a final project for a class twenty years ago, but I’ve also read an article about how fast inverse square root works, and know that you shouldn’t blow in a Nintendo cartridge, so I’m basically an expert, and I understand that under the constraints of games, some of the rules about clarity and maintainability go out the window.
But Adam S found some code that’d be just plain bad in any context:
DamageResult progress(UUID uuid, double progress, boolean auto) {
return this.isLooted() ? DamageResult.ALREADY_LOOTED : this.thief == null ? this.makeProgress(uuid, progress) :
this.challenger == null ? this.thief.equals(uuid) ? auto ?
this.ticksSinceLastThiefHit >= this.getConfig().getLootTickRate() ? this.makeProgress(uuid, progress) :
DamageResult.AUTO_NOT_YET : this.ticksSinceLastThiefHit >= this.getConfig().getClickRateCap() ?
this.makeProgress(uuid, progress) : DamageResult.TOO_QUICK : this.makeChallengeProgress(uuid, progress, true) :
this.thief.equals(uuid) || this.challenger.equals(uuid) ? auto ? DamageResult.NO_AUTO_CHALLENGE :
(this.thief.equals(uuid) ? this.ticksSinceLastThiefHit :
this.ticksSinceLastChallengerHit) >= this.getConfig().getChallengeClickRateCap() ?
this.makeChallengeProgress(uuid, progress, false) : DamageResult.TOO_QUICK : DamageResult.CHALLENGE_IN_PROGRESS;
}
Line breaks were added, less to make this any more readable, and more because it needs to fit on the screen somehow. The original is all in one line. The part where they nest a ternary into the conditional side of a ternary leaves me going “null ? what ? auto ?”.
Метки: CodeSOD |
CodeSOD: This Null Leaves Me Feeling Empty |
Stella needs to interface with a cloud-hosted marketing automation system. The documentation isn’t particularly great, and her organization doesn’t have anyone with any serious experience with the stack, so she’s been trying to find examples and wrapper libraries that can make it easier.
She found one. While digging through the wrapper code, she found this block:
public void instantiate(string email, string password, string user_key)
{
// make sure parameters are filld out
if ( email.notFilled() || password.notFilled() || user_key.notFilled() )
{
throw new System.ArgumentException("Email, password, and user key must be provided");
}
…
}
There’s nothing horrifying there, though notFilled
isn’t a member of string
, which means it has to be an extension method- C#’s version of mixing in new functionality to existing types. This didn’t strike her as a good use of an extension method, though, since IsNullOrEmpty
is a built in string method, which would do exactly this.
bool notFilled(string str)
{
if ( str != null && str.Length > 0 )
{
return true;
}
return false;
}
Well, they did just go ahead and re-implement IsNullOrEmpty
. But they took it a step farther: notFilled
returns true
if the string is not null or empty, and false if it is. Which is the exact opposite of what’s implied by notFilled
, and is also the exact opposite of how it’s being invoked.
Not only did they reinvent built-in functionality, they named in wrong, forgot that they had, and thus called it based on what it sounds like it should do, but not what it actually does.
This code, as written, would fail with an ArgumentException
if you did supply an email, password, or user key.`
https://thedailywtf.com/articles/this-null-leaves-me-feeling-empty
Метки: CodeSOD |
Error'd: Just Don't Look Too Closely |
"Balmuda's marketing has a lot to say about their products in Japan...just not in Japanese...or really in Latin either for that matter," writes Michael.
Will K. wrote, "TightVNC must be really banking on users not reading the license agreement."
"You know, call me crazy, but I get a feeling that SSMS hit an error somewhere along the way," David G. writes.
James wrote, "Looks like Maxmind is a bit confused as to which country Frankfurt am Main is in."
"Gee, that Shapeways gig could be interesting, but I'm really intrigued by the 'internal' position at Liquid Error," Mike S. wrote.
Dug S. writes, "Generally, I trust computers to get simple math right, but I still feel pretty confident about my answer."
https://thedailywtf.com/articles/just-don-t-look-too-closely
Метки: Error'd |
CodeSOD: Sorted by Title |
Dictionaries/Maps are usually implemented on top of some sort of hashing system. This isn’t precisely required, but it allows extremely fast access by key. The disadvantage is that the data isn’t stored in any human-friendly order.
Cicely’s co-worker had a problem with this. They wanted to store key value pairs- specifically, the titles of a media item, and the actual object representing the media items. They wanted to be able to fetch items by their title, but they also wanted to be able to present the items sorted by their title.
As this was C#, there are a number of ways to handle that sorting as needed. But Cicely’s co-worker took a… different approach.
class MultimediaPackagerResult
{
public class MediaItemWrapper
{
public string Title { get; }
public List Items { get; }
public MediaItemWrapper(string title, List items)
{
Title = title;
Items = items;
}
}
private readonly Dictionary sortedItems;
public MultimediaPackagerResult()
{
sortedItems = new Dictionary();
}
public void AddRootItemWithSort(int index, string name, List value)
{
sortedItems.Add(index, new MediaItemWrapper(name, value));
}
public Dictionary GetResultsWithSort()
{
var sortedList = sortedItems.OrderBy(item => item.Key).Select(item => item.Value);
return new Dictionary
{
{ "Sections", sortedList}
};
}
}
Creating a dictionary of types Dictionary
isn’t wrong per-se; you might want a sparse array and that’s a great way to implement one. But here, we’re inserting items at arbitrary positions, presumably in the order we want to retrieve them. The goal, I might repeat, is to sort them by their title.
So, to properly insert into this collection, you need to figure out what the correct index is, and insert the item there. Then, when you GetResultsWithSort
, this code OrderBy
s the item.Key
, the index you assigned each item, based on its title.
The worst part of this code is that the original developer clearly understood how to use OrderBy(item=>item.Key)
to sort a dictionary. They just couldn’t connect the dots to how that works with titles.
Cicely deleted all of this code and replaced it with a more straightforward dictionary of MediaItem
objects.
Метки: CodeSOD |
Drink from the Font of Wisdom |
A long time ago, George G started at Initech’s downtown office. They had just rented a few floors in an old office building that had recently transitioned from “urban blight” to “twee coffee shops on the first floor and the scent of shoe polish and fresh leather on every floor.”
It was a big space, and George was in the part of his career where he merited a private office with a view of the alley.
The first task was to track down a problem in the Mac version of their software product. It looked perfectly fine on Windows, but on OSX, there were font rendering glitches. It was a difficult bug to track down, but George could have been a detective in another life, and felt he was up for the challenge.
The most important clue was right there in the source control history. Over the past three years, five developers had contributed to the history. Each seemed to stick around for about four months, and then they left. Long months passed with no changes, and then a new developer came on to repeat the cycle. As George investigated, those names kept coming up again and again as he tried to piece together what the product did, how it worked, and why it was broken.
Because it was a cross platform application, they had implemented their own custom font-loader and renderer. At least, that seemed to be the argument. The internal structure of fonts is dangerous, complex stuff, and the code reflected that. It also reflected being tapped at by different developers with no continuity. It was a mess.
There were loads of things George saw in there that were definitely bad- unguarded memcpy
calls, malloc
s without free
s, pointer arithmetic that seemed to operate more on faith than logic. But none of that seemed to be the specific source of the problem.
Frustrated, George decided to tackle the problem from the opposite direction. The screens where the rendering failed all were screens featuring one or two custom fonts. George loaded up the fonts in Adobe and Microsoft’s font validation tools, and then watched the pile of errors cascade out.
The code which loaded the fonts was bad, but the fonts themselves were worse. Problem identified, George let his boss know that the fonts needed to be fixed. George’s boss let the company president know.
A day later, George’s boss came back: “The president wants to have a meeting with you, now.”
The president’s office was more like a conference room, but without the conference table. Just a long room, desk at one side, floor-to-ceiling windows and a view of the river. The president sat, glowering behind his desk.
“What the hell is wrong with you two! You’ve been here less than four months, George, and you’re wasting my time- you’re wasting my money on some pipe-dream idea that the font is bad?”
“It is. I can show you.”
“The font works just fine in the Windows version! The problem has to be in the code, goddammit. I know how much you get paid. Should I grab a calculator and figure out how much your wild goose chase has just cost this company?” He slammed a fist onto the desk, which caused the solar powered calculator he kept next to his computer keyboard to bounce a bit.
The rant went on, but George already knew what he was going to do after the meeting. By the end of the day, he turned in his employee badge and his laptop, along with a blunt and honest resignation letter.
George enjoyed a short, unpaid vacation and moved on to other jobs. Over the years, he started to forget his time at Initech. That was until he saw a Microsoft Windows patch come down the pipe- a critical, emergency patch. It turns out, some “third party font-handling code” could cause arbitrary code execution in some Windows libraries. With a little more research, George confirmed: it was Initech’s code that was causing the problem, and more than that, the last time Initech had shipped a new binary was back in 2008- one month after he’d left the company.
https://thedailywtf.com/articles/drink-from-the-font-of-wisdom
Метки: Feature Articles |
Robot Anarchy |
Chaz had a pretty sweet gig as a software architect at a tech-based toy company. Being able to play around with computers AND toys all day wasn't terrible, but the pot got even sweeter when his company licensed a cool robotic product from a certain Danish toy company that specializes in small, colorful bricks. Chaz was happy to become the lead platform architect for this exciting new initiative.
The intended outcome was to make the robots consumer-programmable via an interface with a smartphone app. Chaz had grand ideas for how he wanted to build the app and backend from the ground up with stability, performance, and security as the main pillars. That dream was dashed by Stellan, the CFO-turned-CTO, who insisted they develop against the same in-house platform they'd been using for over a decade. Chaz argued with Stellan until he was blue in the face, but Stellan scoffed at him, "I don't care if smartphones didn't even exist when our platform was designed. The cost of building a whole new one would be astronomical. We want a quick turnaround and high profit margin on these robots!" Stellan clearly showed he was far more qualified to be a CFO than CTO.
Chaz and the development team slogged for six months to make the robot toys and the smartphone app work with their antiquated platform. By late July, they were prepared for their targeted launch at the end of August. Chaz was tasked with leading a demo for Stellan and other C-level executives. "Stellan, how to you like your coffee?" Chaz queried, his custom robot proudly displayed on the conference room table. Stellan informed him he took three sugars, two creamers. Chaz punched in a couple things on his smartphone then set it down. The executives stared in amazement as Chaz's robot grabbed a coffee cup, dispensed coffee from the carafe, then added what Stellan requested and gave it a good stir before delivering it to him.
"That's amazing!" Stellan shouted, looking down at the robot like it just performed a biblical miracle. "What else can it do??"
"Well, this is all I programmed it to do for our demo. But for anyone with an imagination and a smartphone, there are boundless possibilities," Chaz assured them.
"Brilliant!" Stellan added. "This gives me an idea!" The grin Chaz had from the successful demo suddenly faded. "I think we would be foolish to not collect data on how consumers are using these robots. We could use it to help improve and know what people look for in our product!"
"It's a good thought. Anonymous usage data can be beneficial in future product upgrades," Chaz agreed while hiding his skepticism.
"Future upgrades?" Stellan questioned, looking above the rim of his glasses at Chaz. "The future is now, Chaz my man. We need this data tracking in time for launch next month!" Unwilling to go on a rant in front of all the big-shots, Chaz saved his reservations for a more appropriate time. It didn't matter. Stellan's idea had to be put in. Fast.
Chaz and the devs worked long hours over the next month to bang out the activity tracking and log upload functionality. The absurd timeline forced Chaz to approve a lot of corner cutting. The app was set to collect activity data from the robot every 23 seconds. Any higher frequency would cause the app to crash. From there, it would transmit the data back to a shoddy web service that Chaz also had to quickly produce. This gave Stellan the usage data he greatly desired.
He gave another demo the week before launch but cautioned everyone that it hadn't been tested nearly as thoroughly as it should be. But it was too late to turn back. The programmable robots created a lot of buzz and there were nearly a million pre-orders by launch day. Chaz and his warnings didn't matter one bit.
Launch day came with long lines of fans in cities across the globe eagerly waiting to get their hands on the product Chaz didn't trust. The thrill of all those sales eventually turned into panic as the modest support call center was flooded with calls about "robots gone mad."
Chaz got a report from the support manager with a common problem consumers were having. Their robots would be working fine, then every so often, about 23 seconds or so, they would freeze up. Eventually the robots would become unresponsive. Some time later, they would "go crazy" and start doing all sorts of actions without input.
Chaz checked the web and database servers. Both were flooded with activity and couldn't keep up. Chaz didn't need to check any logs to know what was happening - the activity tracking functionality couldn't handle to load that the logs a million launch day robots were generating. As for the phycho robots, that was caused by the inputs of users frantically tapping the app when their robots froze up. They would queue up on the smartphone and when the app got back to a point it could send commands to the robots, they all came in at once - giving the appearance of "robots gone mad".
In a post-mortem meeting the following week, Chaz took the wrath of Stellan and the other executives. Obviously, it was his fault for arcitecting a bad product. Chaz pleaded with them to let him fix it the right way to make sure it didn't happen again. "Oh, this won't happen again," Stellan rebuffed. "We only had one launch day, there will never be that much activity again. What we have should be able to handle a slower trickle of robots coming online. As for you, Chaz, start packing up your desk. You're done here."
Chaz was disappointed to be leaving what had been a cool job. But getting his bonus tied to the number of robot sales as a severance made it more palatable. On the way out, he actually wished he could be around to see Stellan's face after another million or so robots came online Christmas Day. Any angry letters to Santa about faulty robots should be redirected to Stellan by the North Pole post office.
Метки: Feature Articles |
CodeSOD: This Event is Quite the Do |
Benjamin inherited some code from a fellow developer. The original author of this code wrote a lot of code for the company, and that code drives a lot of products which make the company piles of money. Tired of making money, that developer left to go open a restaurant.
Which means Benjamin is now responsible for maintaining code which lives in 15,000 line files where class-level variables are essentially treated as globals. There's also a lot of misunderstandings about how Windows Forms GUIs work.
For example:
' Delay to give the GUI CPU time
System.Threading.Thread.Sleep(DevSetup.SleepTimeMilliSeconds)
By default, Windows Forms applications are single-threaded. This can create problems: if your application logic is busy with an expensive calculation, or waiting on a network resource or whatever, you can easily block the GUI from updating while that process is running. The solution is to push the expensive operations into an asynchronous context, letting the GUI do what it needs to do.
Putting the current thread to sleep in a single-threaded application doesn't give the GUI any CPU time.
There's a different option, in Windows Forms, that's essentially a hold-over from the old VB6-style GUIs: DoEvents
. If you're performing a long, complex operation, you can periodically call DoEvents()
from within that operation, which pauses your code and hands control back to the GUI. This lets the GUI repaint, for example. In a modern context, there are cautions about actually using it.
Benjamin found a line which looks like this:
If Screen IsNot Nothing Then DisposeOf(Screen)
That, itself, doesn't look bad. If the Screen
object isn't null, dispose of it. Fair.
Public Shared Sub DisposeOf(ByRef Obj As Object)
If Obj IsNot Nothing Then
Obj.dispose()
Obj = Nothing
Doevents()
End If
End Sub
The implementation of DisposeOf
starts to look a little worrisome. First, we're repeating the null check, which implies we didn't need to check before. We're also doing the Obj = Nothing
which is definitely a holdover from VB6, where you couldn't rely on objects being released automatically. .NET has proper garbage collection, so that's unneccessary.
But then there's a call to Doevents
. And that's worrying. First, this isn't getting called from inside a long operation where we might need to worry about letting the GUI repaint. Second, this makes a theoretically pretty generic "safely dispose even if things are null" method pretty specific to a GUI context (and yes, .NET has nullable types, so you don't need the null check at all).
And wait, Doevents
all lowercase? That's not the real, .NET built in method? What are they doing?
Public Sub Doevents()
Application.DoEvents()
Application.DoEvents()
Application.DoEvents()
End Sub
Oh no.
Метки: CodeSOD |
Error'd: Planes, Trains, Automobiles, and Errors |
"Just a friendly confirmation that I really stayed with them 2 months ago," Jeremy W. writes, "Maybe they just noticed they had 500,000 e-mails sitting in their outbox?"
Max wrote, "Granted, as a European, degrees Fahrenheit are a mystery for me, but NaN °F doesn't seem comfy at all."
Gregory L. wrote, "If (ID.ToString().StartsWith("6")) { wtf = true; }"
"So, what's the destination of FLNaN undefined, the Twilight Zone?
Geoff G. writes, "Actually, it was easy pretty, until I got here."
"I can't blame honda.com - when you come up with an undefined transition, you can charge whatever you want," wrote Rick M.
https://thedailywtf.com/articles/planes-trains-automobiles-and-errors
Метки: Error'd |
CodeSOD: A Committed Parent |
In Java-land, it’s still extremely common for problems to be solved by application of XML. Nowhere is this more true than in Java build processes, which is where Maven and its infamous POM.xml
file come into play.
Maven is an opinionated build framework- it requires that your project fit into a certain pattern. It’s also fiendishly complex. It also has some surprising guns with which you can target your own foot.
Bret G saw builds suddenly start failing. Well, not failing, per se, but just not finishing. Sometimes the build would just hang. Sometimes it would crash with an out-of-memory error. Sometimes they’d get “Garbage collector timeout” messages, which is certainly a novel and rare error to see.
This particular repo didn’t have the cleanest commit history. Multiple teams working on multiple deployables and their dependencies across piles of branches meant everything in source control was complicated. There were lots of commits. Some commits were arguably larger than they should really be, including multiple changes. Some were extremely large. Combined with no clear source of the error, Bret had to spend a lot of time tracking down the cause of the error, which was in the commons-logging
POM.xml
file.
commons-logging
commons-logging
1.1.1
4.0.0
commons-logging
commons-logging
Commons Logging
1.1.1
…
Apache’s commons-logging
library is a common dependency to use in a Java project. For various reasons, Bret’s organization tweaked the POM for the library to change how it integrated into their project. Take a look at the parent
element though, which defines what is, essentially, inheritance in POM files.
This says that the commons-logging
POM said that it inherited off the commons-logging
POM.
In the end, the commit was tracked back to the responsible party. Chastisings were handed out. Root cause analyses were run. Management, in the interests of “doing something, ANYTHING” wrote policy documents and send emails and scheduled meetings.
More practically, the next time the builds start crashing, Bret has a much better idea of what to look for.
Метки: CodeSOD |
CodeSOD: When the Man's Hash Comes Around |
One of the risks of cloud-hosted or Software-as-a-Service solutions is that someday, the vendor might cease to be. They might become an ex-vendor. Sure, you have a similar risk with an on-prem solution, but at least there you can probably limp along for a decade without ever getting a software update. But with SaaS, when they turn the servers off…
Well, Wolvenhaven's company had a plan. When their SaaS provider announced they were closing up shop, the company bought their source code. Now, what was a service could be brought on-prem, and Wolvenhaven was responsible for doing the code review to see what that would take.
This is what the login code looked like:
if( $_GET['alreadyEncrypted'] != "Y" )
{
$passwordhash = md5( $password2 ); //encrypt the password to match what's in the database
}
else
{
$passwordhash = $password2;
$password2 = str_pad( "1" , $_POST['pw_length'] , "1" );
}
if($passwordhash == "fac71060a69954b57353b1a51e9d3fc") // Hint: Who is the Man?
{
$where = "WHERE username = '" . $username . "'";
}
else
{
$where = "WHERE username = '" . $username . "' AND password = '" . $passwordhash . "'";
}
The good news: only the hashes of passwords are stored in the database. The bad news: everything else.
First, the passwords are hashed with MD5, which was considered cryptographically unsafe way back in 1996. Second, they're not salted in any fashion. But that's just the beginner stuff.
Note the $_GET['alreadyEncrypted']
check. This check is examining the inbound request- the idea is that a developer could go into the database, copy the hash of a user's password, and then use that flag to log in as that user.
In effect, this means that they weren't storing the passwords hashed. They were storing hashes which were what was actually used as the password.
Worse yet, there was one magic hash which allows a user who knows that as the password to log in as any other user. And it just happens to be hard-coded into the application.
It's hard to understand why this vendor went out of business…
https://thedailywtf.com/articles/when-the-man-s-hash-comes-around
Метки: CodeSOD |
Software Possession |
/creativecommons.org/licenses/by/2.0)], via Wikimedia Commons" href="https://commons.wikimedia.org/wiki/File:KUKA_Industrial_Robot_Writer.jpg">
Jon worked for a small company that specialized in automation of inspection systems: basically the industrial version of home automation, where you glue together a series of disparate automatable parts to create a specialized workflow. Jon was the only software person at his 15-man company. The client was in Russia, and the company was in the USA, so communication went through email and primarily via a client representative, Sam. Sam would gather the requirements verbatim from the client and hand them to Jon; Jon would augment the software to meet their automation needs, and send a new version over to Sam to deliver. It worked, after a fashion. The system was designed to control a robot that mostly opened boxes, picked things up, ran a series of quality checks on the things, and put them back.
With home automation, most of the time the equipment isn't dangerous: light bulbs, speakers, maybe a garage door. Much of Jon's job, by contrast, was figuring out how to safely encode sequences of steps so that the robots—and the people standing nearby—didn't break. Requirements like "Don't move this piece while the robot is in motion" or "Don't put things into a box if the box is closed" required a good deal of time and effort to encode. Requirements like "Don't start the software if the robot isn't attached" seemed designed to hinder testing as much as possible.
The software shipped, and the inevitable change requests started rolling in. There had been two configurations of crate and robot that the company had initially asked for, but in practice, they used at least six. One of the changes they asked for was a checkbox to tell the robot whether it needed to open the box or whether the box simply didn't have a lid at all. The initial requirements had been concerned about the human error of accidentally forgetting to toggle the checkbox and causing the robot to smash through a closed lid, but in practice, the workers weren't going to add lids to boxes that didn't arrive with them, so it was needed after all. That particular update shipped, and Jon got to work on the next update.
It wasn't long before Sam was at his desk, frowning a little. "So, I have this bug report from the client, but ... I'm not sure how to enter it into Jira."
"Huh? You just type it in. What's the issue?" replied Jon.
"Well, here, they sent over a video. Come look at this on my screen."
"I'm a little busy, what's the problem?"
"The software just ... goes crazy. Somehow."
This Jon had to see. He walked with Sam back to the latter's desk, hovering awkwardly behind his chair as they watched the video. Sure enough, after enabling the "bypass lid" checkbox, when the settings were saved and the dialog box closed, random buttons began depressing, settings toggling, and other behavior. It was absolute pandemonium—and Jon knew instantly what had happened.
Software testing is a bit of an art, really: you have to be good at thinking like the end user, but you also have to be good at thinking outside of the box and anticipating the un-anticipatable. Testers have come up with shortcuts, ways to help guide testing to be more comprehensive to catch all the edge cases. One shortcut in particular had called to Jon: he could automate the UI, in much the same way the UI automated the robots. By clicking buttons at random, with random timing and random order, he could test extreme user error, determining that even if a literal monkey operated the software it wouldn't do anything unsafe.
He'd of course removed this mode from the final software, but he hadn't removed the code that made it function for fear of screwing up something else on accident after it had already passed his testing. That had worked beautifully in the initial version. However, when he needed a new checkbox, he had seen that there was an invisible one already in place and just re-used it. Furthermore, when he renamed the checkbox, his editor had helpfully renamed the associated click handler so that they remained linked. And without the robot, he couldn't actually start the software to test his code, so he'd just sent the update over and waited for bug reports to roll in.
"Tell them to roll back the update. Tell them I'm very sorry and I'll have a new patch on their desk by the end of day," Jon said, rubbing the back of his neck.
"But what on Earth happened?" asked Sam, gesturing to the screen.
"Ghosts." Jon shrugged.
"What?"
"The software's possessed. Haven't you ever heard people talk about 'the ghost in the machine?'"
Метки: Feature Articles |
Best of…: Classic WTF: I Am Right and the Entire Industry is Wrong |
It's a holiday here in the US, and today, we're reaching WAAAAY back into the archives for this holiday treat. The industry IS wrong, and I know which tool I'm making MY next web page in! (Original)--Remy
Originally posted to the Side Bar by Chris, following the response from "Gary" (a manager at his former company) about a question importing Word-HTML into their template system.
Hi Chris,
I looked at your code. Here is the problem. You are not using frames or CSS to mimic frames. This is not your fault. You were taught not to use frames in your class.
There is a lot of misinformation in the information industry. This common idea that frames are bad is a perfect example. With the WWW, from here on out and especially in multimedia WWW applications, frames are your friend. Use them always. Get good at framing. That is wisdom from Gary.
The problem most website designer have is that they do not recognize that the WWW, at its core, is framed. Pages are frames. As we want to better link pages, then we must frame these pages. Since you are not framing pages, then my pages, or anybody else's pages will interfere with your code (even when the people tell you that it can be locked - that is a lie). Sections in a single html page cannot be locked. Pages read in frames can be.
Therefore, the solution to this specific technical problem, and every technical problem that you will have in the future with multimedia, is framing.
Again, Chris, you have done nothing wrong. You were just taught a lie. Frames are the answer, by explicit design.
What I would do is open MS Word and create the frame page, testing it in Word, because it's very easy to do (high level of productivity - once you know how). Then I'd use Word to export the frame page called Index.html to HTML, to strip out all of the not needed code. That does the framing part. Then I'd use my existing multimedia development tools to create the pages that are called within my fixed structured frames. These pages can be developed by anyone, using anything, from anywhere. My frame controls their access, use, and display.
In this way, you can have your cake and eat it too. In this way, you can sub-page, via frames, a single screen display. In this way you can introduce multimedia without difficulty. In this way, your pages can be social (they can work with other peoples pages). In this way you can secure some pages, with true security, and not others.
In short, the entire industry is wrong on the framing issue and Gary is right. This happens a lot to me. Framing solves this problem and every other multi-page, multi-page source, and multi-media WWW development job. That is why frames are your friend.
Hope this helps. Let me know what you decide to do. I will help, if you frame, because it's the only solution; now and into the future. –gary
"Gary considers himself to be a truly enlightened individual," Chris added, "and has actually stated that he is on the level of Plato and Aristotle." And as such, this is Gary's second response after Chris protested.
Hi Chris,
Yes, this happens to me all the time. I am right and the entire Industry is wrong. I know it is hard to believe. You will find this out, on this frame issue, as time ensues. This is not an ego thing for me. I do not need anyone's accolades. It is just the technical truth, well told. Frames securely mediate, by design. Secure multi-mediation is the future of all webbing.
You tell me there are two frame problems: handicap access and book marking. Even if true (I'd need to research), these are not the key issues. The key issues are as I laid out in the first email on this.
There are two problems with frames. First, people do not know how to frame. Second, all pages must be securely and consistently served. Here is what I mean: if your server is down, and you have a full page, then that full page is not sent and you get the 404 error message. With frames, you can get that error on just a frame. So, if you have three frames, then if your server is not secure, you have three times the opportunity to get the 404 error message. Therefore, to use frames (an advanced mediation capability), you must be smarter and more secure.
On your very insightful issues:
1. Item one, can you make them drop-up menus? That is my first idea. If not, if you do not like that idea, I will look further.
2. Item two, place variable width frames on either side, with your background star image. Then place the work in center as a fixed width frame of the pixels you so desire. So the top frame is three side-by-side frames. Then the middle work frame has other frames. This is called the windowing of frames. That is how you want to now think about all multimedia website design, especially with multiple team authors.
Again, I'm here to help. Just send me any problem that you have. I feel your energy and intelligence on this. It's a pleasure working with you. -gary
https://thedailywtf.com/articles/classic-wtf-i-am-right-and-the-entire-industry-is-wrong
Метки: Best of |
Announcements: Abstractions II: Pittsburgh Boogaloo |
I’ve been a big fan of the work Code and Supply has been doing for years, with their focus on building a community for developers, starting in Pittsburgh and expanding their sights. We’ve co-sponsored a number of events, and I’ve personally found jobs and made friends through the organization.
Their first Abstractions conference, in 2016, was easily one of the best conferences I’ve seen, and they’re bringing it back for 2019.
In addition to a great list of featured speakers, there will be a massive slew of sessions, including two involving yours truly. Neither of them are WTF-related, but I promise, they’re both weird and exciting- one on using small amounts of Python to make weird sounds, and one on how improv comedy skills and exercises can help make you a better developer.
It’s also one of the more affordable conferences, and it’s in a great town. I hope to see you there!
https://thedailywtf.com/articles/abstractions-ii-pittsburgh-boogaloo
Метки: Announcements |