Dilbert





The Daily WTF

Error'd: A Right to Remain Ever Conscious Blooms;

Eion R wrote, "Sure Google Voce, that is exactly what I was looking for."

 

"One might think this game is titled 'Alpha Blending and the Revenge of Floating Point' but it's not. It's just broken," writes Ashley A.

 

Bryan S. wrote, "I just hope that whoever created this survey doens't work on their online banking app."

 

"Now that it's the end of the day, I'm pretty sure I've walked some finite, non-negative number of steps," Drew C. writes.

 

"Why yes, I am interested in supporting the https project on Indiegogo. I think it'll be a big hit," writes Adam R.

 

"I guess I can't fault the hotel for trying to make some of its money back by including ads in their 'goodbye' note," wrote Andreas R.

 

[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.


CodeSOD: Tryception;

"If at first you don't succeed, try, try again."

We have all encountered situations where we need to attempt an operation, with full knowledge that the operation might very well fail. And if it does, we should retry it. Usually after a delay, usually with a maximum number of retries.

Today's anonymous submitter inherited a site-scraping application. Already, we're in dangerous territory- site-scraping is inherently fragile, dangerous code. It's more dangerous, of course, when it's written by the culprit behind this:

public void ScrapeASite() { try { //Some setup work var doc = HtmlWeb().Load(url); //a synchronous call //use the returned data to do stuff } catch(Exception e) { //recurse, and hope the next request for the same domain //gets a different host from the load balancer try { Console.WriteLine(DateTime.Now + " " + BAD SERVER!!! " + e.Message); } catch(Exception) { } //Rinse Repeat ScrapeASite(); } }

The Load method getting called is synchronous, which certainly makes this code simpler, even if it's probably not the best idea. If what goes wrong is a timeout, you might be waiting quite awhile as your program hangs.

And when something does go wrong, we handle the exception.

I'm first delighted to see that Console.WriteLine is wrapped in a try/catch. We can't be too careful, I suppose. We'll just swallow that exception, if it happens, and then we call ScrapeASite. Recursively.

This is C#. The .NET runtime does support tail call optimizations, but the compiled Intermediate Language needs to contain certain op-codes to enable it. The F# complier emits those op-codes. The C# compiler does not.

So if the site goes down, or the network is out, or what have you, we start sending request after request by piling frame after frame up on the call stack. The good news is that this method probably only uses a relatively small amount of space on the call stack, which means you can do this many many times before getting a StackOverflowException.

Perhaps the person responsible for this code should try, try, try a little harder to catch their own mistakes.

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


CodeSOD: A Profitable Education;

Today’s anonymous submitter is an experienced Python developer. Their team is significantly less experienced. In the interests of training, someone suggested, “Perhaps we should buy books for everyone.” Our submitter was handed a stack of possible books, and asked to pick the best one to help the team mature.

One book spent some time discussing types, and the conversion between them. By way of example, it provided a handy method which would turn a string into a floating point number:

def str_int(s):
    val = "%.2f" % profit
    return float(val)

According to the book, this method turns a string into a float, which is why it’s called str_int.

"%.2f" % profit is one of several Python string formatting conventions, and it will take the contents of the variable profit and substitute them where the % appears in the string. In this case, it will be formatted as a floating point with two decimal places. Oh, but wait a moment, the .2f format token requires whatever is being substituted in actually be a floating point value, so the contents of profit couldn’t possibly be a string, or this would fail.

Which, of course, brings us to the largest problem with this code. profit is not the parameter passed in. The parameter passed in is s. s is not used in the method. profit is not declared anywhere in this scope, and according to our submitter, wasn’t declared in any scope.

What this method actually does is crash. What it means to do is take the contents of a floating point variable, truncate it to two decimal places, and then returns it as a float, after taking a round-trip through a string. Which is not the best way to do this in the first place, and it certainly isn’t even the simplest.

I suspect the variable names betray the author’s actual goal for the book: not education, no the respect of their peers, but simply put: profit. The errors in this volume mean that they can work up a second edition, which both corrects these and adds entirely new errors, to promote the third edition!

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


Representative Line: An Equal Crunch;

Rina works in an environment which tends to favor crunch. It's a bit of a feast or famine situation, where they'll coast for months on a pretty standard 9-5 schedule, and then bam, suddenly it's 18 hours days.

No one particularly likes those periods, and code quality takes a nosedive. Co-worker Rusty, though, starts making utterly bizarre decisions when stressed, which is how Rina found this line while doing a code review:

int count = stackRepository.getQueryCount(queryPredicate); if(count > 0 && count < 2) { stackEngine.process(); }

"Um... what exactly are you doing with this?" Rina asked.

"Oh, yeah, well, we shouldn't call the process method unless the count is exactly equal to one," Rusty replied.

"Equal to one," Rina repeated, slowly.

Rusty facepalmed. "Crap. You're not gonna tell anyone about this, are you?"

"Your secret's safe with me," Rina said.

That line got caught before going too much further, but when things get really crunched, code reviews start to go out the window. Who knows what other strange choices lurk in that codebase?

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


CodeSOD: To Round a Corner;

Last week we saw an attempt to reinvent the ceil function. Tina raised a protest: "6 lines to re-implement a ceil function? We can do better."

//Rounds to 1000d Superior public int round1000dSup(int value_To_Round) { int finalResult = 0; int resultIntermediate = value_To_Round / 1000; resultIntermediate += 1; int valueRounded = resultIntermediate * 1000; if ((valueRounded - value_To_Round) == 1000) { finalResult = value_To_Round; } else { finalResult = valueRounded; } return finalResult; }

This isn't a deeply terrible stab at solving the problem. It's bad, certainly, but it's not an eye-gouging horror. It rounds up to the nearest thousand. It takes an odd-way round to get there, but it works.

This method sits in the middle of a 6000+ line class called Utilities. It sits next to methods like this one, also for rounding:

//Rounds to 100d closest public int round100tClose(int value_To_Round) { int finalResult = 0; int resultInteger = value_To_Round / 100; System.out.println("Result integer: " + resultInteger); int remainderDivision = value_To_Round % 100; System.out.println("Remainder of division in integer: " + remainderDivision); if (remainderDivision < 50) { finalResult = resultInteger * 100; System.out.println("Final resul in range < 50: " + finalResult); } else { int valueRounded = (resultInteger * 100) + 100; System.out.println("Final resul in range > 50"); if ((valueRounded - value_To_Round) == 100) { finalResult = value_To_Round; System.out.println("Final resul on Value already Round: " + finalResult); } else { finalResult = valueRounded; System.out.println("Final resul on value not round: " + finalResult); } } return finalResult; }

Now, we can see that the comments follow a... convention, of sorts. I like the addition of a bazillion printlns, which explains a lot about this code, perhaps more than you think.

Tina inherited this project, and the project's inception was a manager going, "Hey, why should we pay an expensive senior developer to ride herd on a pile of juniors? They all went to college. Let's just have a team of all juniors doing development."

This code is clearly someone's repurposed homework. Sometime during their freshman year, they needed to round numbers, and hacked away until they had this. They handed it in, and probably got a "B", were happy with the grade and moved onto the next assignment.

There we have it: a giant do-anything class, written by people who are still learning the job, without sufficient supervision, released into the wild, until it lands on Tina's desk, where she now gets to try and clean out the overgrowth and turn it into something maintainable.

"At least," she adds, "it's not copy-pasted anywhere else... or is it?"

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


Error'd: The Reason is NULL;

"Turns out that you shouldn’t use your edge browser to download Chrome because of potentially malicious links and...null," wrote Allen B.

 

Timothy W. writes, "On the surface, it seems that whomever sent this phishing email seemed to know I work in the wardrobe department of a major movie studio. I realized too late that it was just a typo."

 

"That big old green check is ...misleading, or was this a successful error? I'm in emotional limbo," wrote Lucy W.

 

David S. writes, "The genius of this is that it protects your accounts in two different ways. Not only does it block your cards from being skimmed(without needing batteries!), at its sale price of £495 it ensures that your bank account won't have any money in it to get stolen!"

 

"I don't remember signing up for the Classmates website in 1970, I didn't even get a computer until 1989, but if they say I did, sure I guess so!" Raymond L. wrote.

 

Andrea writes, "It's pretty cool that a certain well-known email app has started offering 'quick replies', but I'm not feeling it's fully baked yet."

 

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


CodeSOD: A Swift Update;

Banks are uniquely identified via a “SWIFT Code”. It’s an ISO Standard. Having an accurate SWIFT code for a given bank is of vital importance to anyone doing financial transactions. With mergers, moves, new branches, and so on, the SWIFT codes you do business with won’t change often, but they will change.

Thus, Philip wasn’t terribly surprised when he got a request to update a pile of SWIFT codes. He couldn’t make the change via the database, though, as no one had permission to do that. He couldn’t edit it through an application UI, because no one had ever built one.

Instead, he had to check out a Java web service from SVN, modify the hard-coded values in the code, deploy the service to production (an entirely manual process), and then invoke the web service via cURL.

      @GET
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	@Path("/writeAccountTableOther/{namespace}")
	public Response writeAccountTableOther(@PathParam("namespace") String namespace) {		
		NamespaceManager.set(namespace);
		List<String> accounts = Arrays.asList( new String[] {
				"999,Initech Financial Svcs    	,ABC123   ",
				"998,Initech Investment          	,BBC123  " ,
				"997,Initech BIC                ,CBC123  " ,
				"996,Initrode Bank          	,DBC123  " ,
				"995,Initrode Comercial               	,ABC223  " ,
				"994,Initrode Industrial Bank           	,FFF123   ",
				"993,Initrode Millenium Bank                 	,GAB123   ",
				"992,Initech Holdings         	,QBC512   ",
				"991,Initech Spirit Bank             	,IIL512   "
		});

		for (String account : accounts) {
			String[] split = account.split(",");
			int i=0;
			Entity entity = new Entity("bni_other_acc", split[i].trim());
			entity.setProperty("NIBBank", split[i++].trim());
			entity.setProperty("Name", split[i++].trim());
			entity.setProperty("SwiftCode", split[i++].trim());
			DatastoreServiceFactory.getDatastoreService().put(entity);
		}						
		return Response.status(Response.Status.OK).entity("DONE").build();
	}

This was the only mechanism for modifying these data values.

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