News Roundup: EquiTF |
We generally dont do news roundups when yet another major company gets hacked and leaks personally compromising data about the public. We know that big company hacked isnt news, its a Tuesday. So the Equifax hack didnt seem like something worth spending any time to write an article about.
But then new things kept coming out. It got worse. And worse. And worse. Its like if a dumpster caught on fire, but then the fire itself also caught on fire.
If you have been living under a rock, Equifax, a company that spies on the financial behavior of Americans and sells that intelligence to banks, credit card companies, and anyone else whos paying, was hacked, and the culprits have everything they need to steal the identities of 143 million people.
Thats bad, but everything else about it is worse. First, the executives kept the breach secret for months, and then sold stock just before the news went public. That is a move so utterly brazen that they might as well be a drunk guy with no shirt shouting, Come at me bro! Come at me! Theyre daring the Securities and Exchange Commission to do something about it, and are confident that they wont be punished.
Speaking of punishment, the CEO retired, and hell be crying about this over the $90M hes collecting this year. The CIO and CSO went first, of course. They probably wont be getting huge compensation packages, but Im sure theyll land cushy gigs somewhere.
Said CSO, by the way, had no real qualifications to be a Chief Security Officer. Her background is in music composition.
Now, I want to be really clear here: I dont think her college degree is actually relevant. What you did in college isnt nearly as important as your work experience, which is the real problem- she doesnt really have that, either. Shes spent her entire career in executive roles, and while she was a CSO before going to Equifax, that was at First Data. Funny thing about First Data: up until 2013 (about when she left), it was in a death spiral that was fixed after some serious house-cleaning and restructuring- like clearing out dead-weight in their C-level.
Don't worry about the poor shareholders, though. Remember Wells Fargo, the bank that fraudulently signed up lots of people for accounts? They list Equifax as an investment opportunity that's ready to "outperform".
Thats the Peter Principle and corporate douchebaggerry in action, and it certainly starts getting me angry, but this site isnt about class struggle- its about IT. And its on the IT side where the real WTFs come into play.
Equifax spies on you and sells the results. The US government put a mild restriction on this behavior: they can spy on you, but you have the right to demand that they stop selling the results. This is a credit freeze, and every credit reporting agency- every business like Equifax- has to do this. They get to charge you money for the privilege, but they have to do it.
To secure this transaction, when you freeze your credit, the credit reporting companies give you a password which you can use in the future to unfreeze it (because if you want a new credit card, you have to let Equifax share your data again). Some agencies give you a random string. Some let you choose your own password. Equifax used the timestamp on your request.
The hack itself was due to an unpatched Struts installation. The flaw itself is a pretty fascinating one, where a maliciously crafted XML file gets deserialized into a ProcessBuilder object. The flaw was discovered in March, and a patch was available shortly thereafter. Apache rightfully called it Critical, and encouraged all Struts users to apply the fix.
Even if they didnt apply the fix, Apache provided workarounds- some of which were as simple as, Turn off the REST plugin if youre not using it, or if you ARE using it, turn off the XML part. Its certainly not the easiest fix, especially if youre on a much older version of Struts, but you could even patch just the REST plugin, cutting down on the total work.
Now, if youre paying attention, you might be saying to yourself, Hey, Remy, didnt you say that they were breached (initially) in March? The month the bug was discovered? Isnt it kinda reasonable that they wouldnt have rolled out the fix in time? Yes, that would be reasonable: if a flaw exposed in March was exploited within a few days or even weeks of the flaw being discovered, I could understand that. But remember, the breach that actually got announced was in July- they were breached in March, and they still didnt apply the patch. This honestly makes it worse.
Even then, Id argue that were giving them too much of the benefit of the doubt. Im going to posit that they simply dont care. Not only did they not apply the patch, they likely had no intention of applying the patch, because they assumed theyd get away with it. Remember: you are the product, not the customer. If they accidentally cut the sheep while shearing, it doesnt matter: theyve still got the wool.
As an example of they clearly dont care, lets turn our attention to their Argentinian Branch, where their employee database was protected by the password admin/admin. Yes, with that super-secure password, you could log in from anywhere in the world and see the users usernames, employee IDs, and personal details. Of course, their passwords were obscured as ******… in the rendered DOM. A simple View Source would reveal the plaintext of their passwords, in true hunter2 fashion.
Dont worry, it gets dumber. Along with the breach announcement, Equifax took to social media to direct users to a site where, upon entering their SSN, it would tell them whether or not they were compromised. That was the promise, but the reality was that it was little better than flipping a coin. Worse, the site was a thinly veiled ad for their "identity protection" service, and the agreement contained an arbitration clause which kept you from suing them.
That is, at least if you went to the right site. Setting aside the wisdom of encouraging users to put confidential information into random websites, for weeks Equifaxs social media team was directing people to the wrong site! In fact, it was directing them to a site which warns about the dangers of putting confidential information into random websites.
And all of that, all of that, isnt the biggest WTF. The biggest WTF is the Social Security Number, which was never meant to be used as a private identifier, but as its the closest thing to unique data about every American, it substitutes for a national identification system even when its clearly ill-suited to the task.
Ill leave you with the CGP Grey video on the subject:
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: News Roundup |
CodeSOD: An Exception to the Rule |
Throw typed exceptions, is generically good advice in a strongly typed language, like Java. It shouldnt be followed thoughtlessly, but its a good rule of thumb. Some people may need a little more on the point, though.
Alexander L sends us this code:
public boolean isCheckStarted (final String nr) throws CommonException {
final BigDecimal sqlCheckStarted = executeDBBigDecimalQueryFirstResult (
Query.CHECKSTARTED_BY_NR,
nr);
CommonException commonException = new CommonException ("DB Query fail to get 'CheckStarted'");
int checkStarted = -1;
checkStarted = Integer.parseInt (Utility.bigDecimalToString (sqlCheckStarted));
if (checkStarted == 1 || checkStarted == 0) {
return checkStarted == 1 ? true : false;
} else {
throw commonException;
}
}
At a glance, it looks ugly, but the scope of its badness doesnt really set in until Alexander fills some of the surrounding blanks:
CommonException is a generic class for failures in talking to the databaseRuntimeExceptionexecuteDBBigDecimalQueryFirstResult throws a CommonException if the query failed.Its also important to note that Java captures the stack trace when an exception is created, not when its thrown, and this method is called from pretty deep in the stack, so thats expensive.
And all of that isnt even the worst. The CheckStarted field is apparently stored in the database as a Decimal type, or at least is fetched from the database that way. Its only legal values are 0 and 1, making this a good bit of overkill. To round out the type madness, we convert it to a string only to parse it back into an int.
And thats still not the worst.
This line: return checkStarted == 1 ? true : false; Thats the kind of line that just sets my skin crawling. It bugs me even more than using an if statement, because the author apparently knew enough to know about ternaries, but not enough to know about boolean expressions.
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: CodeSOD |
An Emphasized Color |
One of the major goals of many software development teams is to take tedious, boring, simplistic manual tasks and automate them. An entire data entry team can be replaced by a single well-written application, saving the company money, greatly improving processing time, and potentially reducing errors.
That is, if its done correctly.
Peter G. worked for a state government. One of his departments tasks involved processing carbon copies of forms for most of the states residents. To save costs, improve processing time, and reduce the amount of manual data entry they had to perform, the department decided to automate the process and use optical character recognition (OCR) to scan in the carbon copies and convert the handwritten data into text which was eventually entered into a database.
By By Aaron LoganThe software was written and the department received boxes and boxes and boxes worth of the carbon copy paper forms. The printer had a very long lead time, so they ordered their entire supply of forms for the state for the next year. There were so many boxes that Peter joked about building a castle with them.
Then the system went live. And it didnt work, at all. Something was wrong with the OCR software and Peter was pulled into the project to help find a fix.
While researching the project history, he found that much of the data on the paper forms wasnt required, and the decision was made to print those boxes in a different, very specific color. During processing, their custom OCR software would ignore that color, blanking out the box and removing the extraneous information before it was unnecessarily entered into the system. Since it still needed to be visible, but wasnt important, they chose, with the help of their printer, Pantone 5507.
So he filled out a sample form for one Homer J. Simpson and scanned it to see what was meant by The system doesnt work. The system briefly churned and created a record in the test database for his form, but when he inspected the record, it was missing the mandatory unique ID. This ID came from the paper form and was comparable to a license number or Social Security Number, and was absolutely required for the data to be usable.
He filled out a couple more forms in case the system was having trouble understanding his handwriting, but they came out the same way. No unique ID.
He scratched his head and examined the paper forms some more. Eventually, he realized the issue. The box for the unique ID was considered important but not something for users to interact with, and thus was de-emphasized, and prrinted printed in that different, very specific color that the OCR software ignored: Pantone 5507. So the ID was blanked out and ignored during scanning.
Being a competent developer, Peter quickly came up with a plan to add a step to the task. After scanning, but before handing off to the OCR task, a new task would do a simple color-based find-and-replace within a region of the scan to correct the color of the ID field so it wouldnt be blanked out.
No, we dont have time or money for that, his manager explained to him. Ill have the offshore guys fix it for next year. For now, just cobble something together so the original scan stays with the record.
The department hired a team of interns to perform manual data entry for the year, whose sole task was to sift through the database records, pull up the corresponding scan, and read and type in the single unique ID field that the OCR software ignored. Meanwhile, the department promised that something bigger, better, and fancier was on the way for next year&
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: Feature Articles |
CodeSOD: The Strangelet Solution |
Chris M works for a solutions provider. Mostly, this means taking an off-the-shelf product from Microsoft or Oracle or SAP and customizing it to fit a clients specific needs. Since many of these clients have in-house developers, the handover usually involves training those developers up on the care and maintenance of the system.
Then, a year or two later, the client comes back, complaining about the system. Its broken, or performance is terrible, or we need a new feature. Chris then goes back out to their office, and starts taking a look at what has happened to the code in his absence.
Its things like this:
var getAdjustType = Xbp.Page.getAttribute("cw_adjustmenttype").getText;
var reasonCodeControl = Xbp.Page.getControl("cw_reasoncode");
if (getAdjustType === "Short-pay/Applying Credit" || getAdjustType === "Refund/Return (Credit)") {
var i;
var options = (Xbp.Page.getAttribute("cw_reasoncode").getOptions());
reasonCodeControl
for (i = 0; i < options.length; i++) {
if (i <= 4) {
reasonCodeControl.removeOption(options[i].value);
}
if (i >= 5) {
reasonCodeControl.clearOptions();
}
if (i >= 5) {
reasonCodeControl.addOption(options[5]);
reasonCodeControl.addOption(options[6]);
reasonCodeControl.addOption(options[7]);
reasonCodeControl.addOption(options[8]);
reasonCodeControl.addOption(options[9]);
reasonCodeControl.addOption(options[10]);
reasonCodeControl.addOption(options[11]);
reasonCodeControl.addOption(options[12]);
reasonCodeControl.addOption(options[13]);
reasonCodeControl.addOption(options[14]);
reasonCodeControl.addOption(options[15]);
reasonCodeControl.addOption(options[16]);
reasonCodeControl.addOption(options[17]);
reasonCodeControl.addOption(options[18]);
reasonCodeControl.addOption(options[19]);
reasonCodeControl.addOption(options[20]);
reasonCodeControl.addOption(options[21]);
}
}
}
else {
var options = (Xbp.Page.getAttribute("cw_reasoncode").getOptions());
for (var i = 0; i < options.length; i++) {
if (i >= 4) {
reasonCodeControl.removeOption(options[i].value);
}
if (i <= 4) {
reasonCodeControl.clearOptions();
}
if (i <= 4) {
reasonCodeControl.addOption(options[0]);
reasonCodeControl.addOption(options[1]);
reasonCodeControl.addOption(options[2]);
reasonCodeControl.addOption(options[3]);
reasonCodeControl.addOption(options[4]);
}
}
}
There are patterns and there are anti-patterns, like there is matter and anti-matter. An anti-pattern would be the switch loop, where you have different conditional branches that execute depending on how many times the loop has run. And then theres this, which is superficially similar to the switch loop anti-pattern, but confused. Twisted, with conditional branches that execute on the same condition. It may have once been an anti-pattern, but now its turned into a strange pattern, and like strange matter threatens to turn everything it touches into more of itself.
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: CodeSOD |
Error'd: Choose Wisely |
"I'm not sure how I can give feedback on this course, unless, figuring out this matrix is actually a final exam," wrote Mads.
Brian W. writes, "Sorry that you're not happy with our spam, but before you go...just one more."
"I was looking forward to getting this Gerber Dime, but I guess I'll have to wait till they port it to OS X," wrote Peter G.
"Deleting 7 MB frees up 6.66 GB? I smell a possible unholy alliance," Mike W. writes.
Bill W. wrote, "I wonder if they're wanting to know to what degree I'm 'not at all likely' to recommend Best Buy to friends and family?"
"So, is this a new way for the folks at WebEx to make sure that you don't get bad answers?" writes Andy B.
[Advertisement]
Otter, ProGet, BuildMaster – robust, powerful, scalable, and reliable additions to your existing DevOps toolchain.
|
Метки: Error'd |
Tales from the Interview: The In-House Developer |
James was getting anxious to land a job that would put his newly-minted Computer Science degree to use. Six months had come to pass since he graduated and being a barista barely paid the bills. Living in a small town didn't afford him many local opportunities, so when he saw a developer job posting for an upstart telecom company, he decided to give it a shot.
We do everything in-house! the posting for CallCom emphasized, piquing James' interest. He hoped that meant there would be a small in-house development team that built their systems from the ground up. Surely he could learn the ropes from them before becoming a key contributor. He filled out the online application and happily clicked Submit.
Not 15 minutes later, his phone rang with a number he didn't recognize. Usually he just ignored those calls but he decided to answer. "Hi, is James available?" a nasally female voice asked, almost sounding disinterested. "This is Janine with CallCom, you applied for the developer position."
Caught off guard by the suddenness of their response, James wasn't quite ready for a phone screening. "Oh, yeah, of course I did! Just now. I am very interested."
"Great. Louis, the owner, would like to meet with you," Janine informed him.
"Ok, sure. I'm pretty open, I usually work in the evenings so I can make most days work," he replied, checking his calendar.
"Can you be here in an hour?" she asked. James managed to hide the fact he was freaking out about how to make it in time while assuring her he could be.
He arrived at the address Janine provided after a dangerous mid-drive shave. He felt unprepared but eager to rock the interview. The front door of their suite gave way to a lobby that seemed more like a walk-in closet. Janine was sitting behind a small desk reading a trashy tabloid and barely looked up to greet him. "Louis will see you now," she motioned toward a door behind the desk and went back to reading barely plausible celebrity rumors.
James stepped through the door into what could have been a walk-in closet for the first walk-in closet. A portly, sweaty man presumed to be Louis jumped up to greet him. "John! Glad you could make it on short notice. Have a seat!"
"Actually, it's James..." he corrected Louis, while also forgiving the mixup. "Nice to meet you. I was eager to get here to learn about this opportunity."
"Well James, you were right to apply! We are a fast growing company here at CallCom and I need eager young talent like you to really drive it home!" Louis was clearly excited about his company, growing sweatier by the minute.
"That sounds good to me! I may not have any real-world experience yet, but I assure you that I am eager to learn from your more senior members," James replied, trying to sell his potential.
Louis let out a hefty chuckle at James' mention of senior members. "Oh you mean stubborn old developers who are set in their ways? You won't be finding those around here! I believe in fresh young minds like yours, unmolded and ready to take the world by storm."
"I see..." James said, growing uneasy. "I suppose then I could at least learn how your code is structured from your junior developers? The ones who do your in-house development?"
Louis wiped his glistening brow with his suit coat before making the big revelation. "There are no other developers, James. It would just be you, building our fantastic new computer system from scratch! I have all the confidence in the world that you are the man for the job!"
James sat for a moment and pondered what he had just heard. "I'm sorry but I don't feel comfortable with that arrangement, Louis. I thought that by saying you do everything in-house, that implied there was already a development team."
"What? Oh, heavens no! In-house development means we let you work from home. Surely you can tell we don't have much office space here. So that's what it means. In. House. Got it?
James quickly thanked Louis for his time and left the interconnected series of closets. In a way, James was glad for the experience. It motivated him to move out of his one horse town to a bigger city where he eventually found employment with a real in-house dev team.
[Advertisement]
Otter, ProGet, BuildMaster – robust, powerful, scalable, and reliable additions to your existing DevOps toolchain.
|
Метки: Tales from the Interview |
CodeSOD: A Dumbain Specific Language |
Ive had to write a few domain-specific-languages in the past. As per Remys Law of Requirements Gathering, its been mostly because the users needed an Excel-like formula language. The danger of DSLs, of course, is that theyre often YAGNI in the extreme, or at least a sign that you dont really understand your problem.
XML, coupled with schemas, is a tool for building data-focused DSLs. If you have some complex structure, you can convert each of its features into an XML attribute. For example, if you had a grammar that looked something like this:
The Source specification obeys the following syntax
source = ( Feature1+Feature2+... ":" ) ? steps
Feature1 = "local" | "global"
Feature2 ="real" | "virtual" | "ComponentType.all"
Feature3 ="self" | "ancestors" | "descendants" | "Hierarchy.all"
Feature4 = "first" | "last" | "DayAllocation.all"
If features are specified, the order of features as given above has strictly to be followed.
steps = oneOrMoreNameSteps | zeroOrMoreNameSteps | componentSteps
oneOrMoreNameSteps = nameStep ( "." nameStep ) *
zeroOrMoreNameSteps = ( nameStep "." ) *
nameStep = "#" name
name is a string of characters from "A"-"Z", "a"-"z", "0"-"9", "-" and "_". No umlauts allowed, one character is minimum.
componentSteps is a list of valid values, see below.
Valid 'componentSteps' are:
- GlobalValue
- Product
- Product.Brand
- Product.Accommodation
- Product.Accommodation.SellingAccom
- Product.Accommodation.SellingAccom.Board
- Product.Accommodation.SellingAccom.Unit
- Product.Accommodation.SellingAccom.Unit.SellingUnit
- Product.OnewayFlight
- Product.OnewayFlight.BookingClass
- Product.ReturnFlight
- Product.ReturnFlight.BookingClass
- Product.ReturnFlight.Inbound
- Product.ReturnFlight.Outbound
- Product.Addon
- Product.Addon.Service
- Product.Addon.ServiceFeature
In addition to that all subsequent steps from the paths above are permitted, that is 'Board',
'Accommodation.SellingAccom' or 'SellingAccom.Unit.SellingUnit'.
'Accommodation.Unit' in the contrary is not permitted, as here some intermediate steps are missing.
You could turn that grammar into an XML document by converting syntax elements to attributes and elements. You could do that, but Stellas predecessor did not do that. That of course, would have been work, and they may have had to put some thought on how to relate their homebrew grammar to XSD rules, so instead they created an XML schema rule for SourceAttributeType that verifies that the data in the field is valid according to the grammar… using regular expressions. 1,310 characters of regular expressions.
Theres a bug in that regex that Stella needed to fix. As she put it: Every time you evaluate it a few little kitties die because you shouldnt use kitties to polish your car. Im so, so sorry, little kitties…
The full, unexcerpted code is below, so… at least it has documentation. In two languages!
Die Source Angabe folgt folgender Syntax
source = ( Eigenschaft1+Eigenschaft2+... ":" ) ? steps
Eigenschaft1 = "local" | "global"
Eigenschaft2 ="real" | "virtual" | "ComponentType.all"
Eigenschaft3 ="self" | "ancestors" | "descendants" | "Hierarchy.all"
Eigenschaft4 = "first" | "last" | "DayAllocation.all"
Falls Eigenschaften angegeben werden muss zwingend die oben angegebene Reihenfolge der Eigenschaften eingehalten werden.
steps = oneOrMoreNameSteps | zeroOrMoreNameSteps | componentSteps
oneOrMoreNameSteps = nameStep ( "." nameStep ) *
zeroOrMoreNameSteps = ( nameStep "." ) *
nameStep = "#" name
name ist eine Folge von Zeichen aus der Menge "A"-"Z", "a"-"z", "0"-"9", "-" und "_". Keine Umlaute. Mindestens ein Zeichen
componentSteps ist eine Liste g"ultiger Werte, siehe im folgenden
G"ultige 'componentSteps' sind zun"achst:
- GlobalValue
- Product
- Product.Brand
- Product.Accommodation
- Product.Accommodation.SellingAccom
- Product.Accommodation.SellingAccom.Board
- Product.Accommodation.SellingAccom.Unit
- Product.Accommodation.SellingAccom.Unit.SellingUnit
- Product.OnewayFlight
- Product.OnewayFlight.BookingClass
- Product.ReturnFlight
- Product.ReturnFlight.BookingClass
- Product.ReturnFlight.Inbound
- Product.ReturnFlight.Outbound
- Product.Addon
- Product.Addon.Service
- Product.Addon.ServiceFeature
Desweiteren sind alle Unterschrittfolgen aus obigen Pfaden erlaubt, also 'Board', 'Accommodation.SellingAccom' oder 'SellingAccom.Unit.SellingUnit'.
'Accommodation.Unit' hingegen ist nicht erlaubt, da in diesem Fall einige Zwischenschritte fehlen.
The Source specification obeys the following syntax
source = ( Feature1+Feature2+... ":" ) ? steps
Feature1 = "local" | "global"
Feature2 ="real" | "virtual" | "ComponentType.all"
Feature3 ="self" | "ancestors" | "descendants" | "Hierarchy.all"
Feature4 = "first" | "last" | "DayAllocation.all"
If features are specified, the order of features as given above has strictly to be followed.
steps = oneOrMoreNameSteps | zeroOrMoreNameSteps | componentSteps
oneOrMoreNameSteps = nameStep ( "." nameStep ) *
zeroOrMoreNameSteps = ( nameStep "." ) *
nameStep = "#" name
name is a string of characters from "A"-"Z", "a"-"z", "0"-"9", "-" and "_". No umlauts allowed, one character is minimum.
componentSteps is a list of valid values, see below.
Valid 'componentSteps' are:
- GlobalValue
- Product
- Product.Brand
- Product.Accommodation
- Product.Accommodation.SellingAccom
- Product.Accommodation.SellingAccom.Board
- Product.Accommodation.SellingAccom.Unit
- Product.Accommodation.SellingAccom.Unit.SellingUnit
- Product.OnewayFlight
- Product.OnewayFlight.BookingClass
- Product.ReturnFlight
- Product.ReturnFlight.BookingClass
- Product.ReturnFlight.Inbound
- Product.ReturnFlight.Outbound
- Product.Addon
- Product.Addon.Service
- Product.Addon.ServiceFeature
In addition to that all subsequent steps from the paths above are permitted, that is 'Board', 'Accommodation.SellingAccom' or 'SellingAccom.Unit.SellingUnit'.
'Accommodation.Unit' in the contrary is not permitted, as here some intermediate steps are missing.
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
https://thedailywtf.com/articles/a-dumbain-specific-language
|
Метки: CodeSOD |
Poor Shoe |
"So there's this developer who is the end-all, be-all try-hard of the year. We call him Shoe. He's the kind of over-engineering idiot that should never be allowed near code. And, to boot, he's super controlling."
Sometimes, you'll be talking to a friend, or reading a submission, and they'll launch into a story of some crappy thing that happened to them. You expect to sympathize. You expect to agree, to tell them how much the other guy sucks. But as the tale unfolds, something starts to feel amiss.
They start telling you about the guy's stand-up desk, how it makes him such a loser, such a nerd. And you laugh nervously, recalling the article you read just the other day about the health benefits of stand-up desks. But sure, they're pretty nerdy. Why not?
"But then, get this. So we gave Shoe the task to minify a bunch of JavaScript files, right?"
You start to feel relieved. Surely this is more fertile ground. There's a ton of bad ways to minify and concatenate files on the server-side, to save bandwidth on the way out. Is this a premature optimization story? A story of an idiot writing code that just doesn't work? An over-engineered monstrosity?
"So he fires up gulp.js and gets to work."
Probably over-engineered. Gulp.js lets you write arbitrary JavaScript to do your processing. It has the advantage of being the same language as the code being minified, so you don't have to switch contexts when reading it, but the disadvantage of being JavaScript and thus impossible to read.
"He asks how to concat JavaScript, and the room tells him the right answer: find javascripts/ -name '*.js' -exec cat {} \; > main.js"
Wait, what? You blink. Surely that's not how Gulp.js is meant to work. Just piping out to shell commands? But you've never used it. Maybe that's the right answer; you don't know. So you nod along, making a sympathetic noise.
"Of course, this moron can't just take the advice. Shoe has to understand how it works. So he starts googling on the Internet, and when he doesn't find a better answer, he starts writing a shell script he can commit to the repo for his 'jay es minifications.'"
That nagging feeling is growing stronger. But maybe the punchline is good. There's gotta be a payoff here, right?
"This guy, right? Get this: he discovers that most people install gulp via npm.js. So he starts shrieking, 'This is a dependency of mah script!' and adds node.js and npm installation to the shell script!"
Stronger and stronger the feeling grows, refusing to be shut out. You swallow nervously, looking for an excuse to flee the conversation.
"We told him, just put it in the damn readme and move on! Don't install anything on anyone else's machines! But he doesn't like this solution, either, so he finally just echoes out in the shell script, requires npm. Can you believe it? What a n00b!"
That's it? That's the punchline? That's why your friend has worked himself into a lather, foaming and frothing at the mouth? Try as you might to justify it, the facts are inescapable: your friend is TRWTF.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: Feature Articles |
CodeSOD: Mutex.js |
Just last week, I was teaching a group of back-end developers how to use Angular to develop front ends. One question that came up, which did suprise me a bit, was how to deal with race conditions and concurrency in JavaScript.
Im glad they asked, because its a good question that never occurred to me. The JavaScript runtime, of course, is single-threaded. You might use Web Workers to get multiple threads, but they use an Actor model, so theres no shared state, and thus no need for any sort of locking.
Chris Rs team did have a need for locking. Specifically, their .NET backend needed to run a long-ish bulk operation against their SqlServer. It would be triggered by an HTTP request from the client-side, AJAX-style, but only one user should be able to run it at a time.
Someone, for some reason, decided that they would implement this lock in front-end JavaScript, since thats where the AJAX calls were coming from..
var myMutex = true; //global (as in page wide, global) variable
function onClickHandler(element) {
if (myMutex == true) {
myMutex = false;
// snip...
if ($(element).hasClass("addButton") == true) {
$(element).removeClass("addButton").addClass("removeButton");
// snip...
$.get(url).done(function (r) {
// snip... this code is almost identical to the branch below
setTimeout("myMutex = true;", 100);
});
} else {
if ($(element).hasClass("removeButton") == true) {
$(element).removeClass("removeButton").addClass("addButton");
// snip...
$.get(url).done(function (r) {
// snip... this code is almost identical to the branch above
setTimeout("myMutex = true;", 100);
});
}
}
}
}
You may be shocked to learn that this solution didnt work, and the developer responsible never actually tested it with multiple users. Obviously, a client side variable isnt going to work as a back-end lock. Honestly, Im not certain thats the worst thing about this code.
First, they reinvented the mutex badly. They seem to be using CSS classes to hold application state. They have (in the snipped code) duplicate branches of code that vary only by a handful of flags. They arent handling errors on the request- which, when this code started failing, made it that much harder to figure out why.
But its the setTimeout("myMutex = true;", 100); that really gets me. Why? Why the 100ms lag? What purpose does that serve?
Chris threw this code away and put a mutex in the backend service.
|
Метки: CodeSOD |
Error'd: Have it Your Way! |
"You can have any graphics you want, as long as it's Intel HD Graphics 515," Mark R. writes.
"You know, I'm pretty sure that I've been living there for a while now," writes Derreck.
Sven P. wrote, "Usually, I blame production outages on developers who, I swear, have trouble counting to five. After seeing this, I may want to blame the compiler too."
"Whenever I hear someone complaining about their device battery life, I show them this picture," wrote Renan.
"Prepaying for gas, my credit card was declined," Rand H. writes, "I was worried some thief must've maxed it out, but then I saw how much I was paying in taxes."
Brett A. wrote, "Yo Dawg I heard you like zips, so you should zip your zips to send your zips."
|
Метки: Error'd |
CodeSOD: string isValidArticle(string article) |
Anonymous sends us this little blob of code, which is mildly embarassing on its own:
static StringBuilder vsb = new StringBuilder();
internal static string IsValidUrl(string value)
{
if (value == null)
{
return "\"\"";
}
vsb.Length= 0;
vsb.Append("@\"");
for (int i=0; icode>
Im willing to grant that re-using the same static StringBuilder object is a performance tuning thing, but everything else about this is… just plain puzzling.
The method is named IsValidUrl, but it returns a string. It doesnt do any validation! All it appears to do is take any arbitrary string and return that string wrapped as if it were a valid C# string literal. At best, this method is horridly misnamed, but if its purpose is to truly generate valid C# strings, it has a potential bug: it doesnt handle new-lines. Now, Im sure that wont be a problem that comes back up before the end of this article.
The code, taken on its own, is just bad. But when placed into context, it gets worse. This isnt just code. Its part of .NETs System.Runtime.Remoting package. Still, I know, youre saying to yourself, In all the millions of lines in .NET, this is really the worst youve come up with?
Well, it comes up because remember that bug with new-lines? Well, guess what. That exact flaw was a zero-day that allowed code execution… in RTF files.
Now, skim through some of the other code in wsdlparser.cs, and you'll see the real horror. This entire file has one key job: generating a class capable of parsing data according to an input WSDL file… by using string concatenation.
The real WTF is the fact that you can embed SOAP links in RTF files and Word will attempt to use them, thus running the WSDL parser against the input data. This is code thats a little bad, used badly, creating an exploited zero-day.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
https://thedailywtf.com/articles/string-isvalidarticle-string-article
|
Метки: CodeSOD |
CodeSOD: You Absolutely Don't Need It |
The progenitor of this story prefers to be called Mr. Syntax, perhaps because of the sins his boss committed in the name of attempting to program a spreadsheet-loader so generic that it could handle any potential spreadsheet with any data arranged in any conceivable format.
The boss had this idea that everything should be dynamic, even things that should be relatively straightforward to do, such as doing a web-originated bulk load of data from a spreadsheet into the database. Although only two such spreadsheet formats were in use, the boss wrote it to handle ANY spreadsheet. As you might imagine, this spawned mountains of uncommented and undocumented code to keep things generic. Sin was tasked with locating and fixing the cause of a NullPointerException that should simply never have occurred. There was no stack dump. There were no logs. It was up to Sin to seek out and destroy the problem.
Just to make it interesting, this process was slow, so the web service would spawn a job that would email the user with the status of the job. Of course, if there was an error, there would inevitably be no email.
It took an entire day to find and then debug through this simple sheet-loader and the mountain of unrelated embedded code, just to find that the function convertExcelSheet blindly assumed that every cell would exist in all spreadsheets, regardless of potential format differences.
[OP: in the interest of brevity, I've omitted all of the methods outside the direct call-chain...]
public class OperationsController extends BaseController { private final JobService jobService; @Inject public OperationsController(final JobService jobService) { this.jobService = jobService; } @RequestMapping(value = ".../bulk", method = RequestMethod.POST) public @ResponseBody SaveResponse bulkUpload(@AuthenticationPrincipal final User activeUser, @RequestParam("file") final MultipartFile file, final WebRequest web, final HttpServletRequest request){ SaveResponse response = new SaveResponse(); try { if (getSystemAdmin(activeUser)) { final Map<String,Object> customParams = new HashMap<>(); customParams.put(ThingBulkUpload.KEY_FILE,file.getInputStream()); customParams.put(ThingBulkUpload.KEY_SERVER_NAME,request.getServerName()); response = jobService.runJob((CustomUserDetails)activeUser,ThingBulkUpload.JOB_NAME, customParams); } else { response.setWorked(false); response.addError("ACCESS_ERROR","Only Administrators can run bulk upload"); } } catch (final Exception e) { logger.error("Unable to process file",e); } return response; } } @Service("jobService") @Transactional public class JobServiceImpl implements JobService { private static final Logger logger = LoggerFactory.getLogger(OperationsService.class); private final JobDAO jobDao; @Inject public JobServiceImpl(final JobDAO dao){ this.jobDao = dao; } public SaveResponse runJob(final @NotNull CustomUserDetails user, final @NotNull String jobName, final Map<String,Object> customParams) { SaveResponse response = new SaveResponse(); try { Job job = (Job) jobDao.findFirstByProperty("Job","name",jobName); if (job == null || job.getJobId() == null || job.getJobId() <= 0) { response.addError("Unable to find Job for name '"+jobName+"'"); response.setWorked(false); } else { JobInstance ji = new JobInstance(); ji.setCreatedBy(user.getUserId()); ji.setCreatedDate(Util.getCurrentTimestamp()); ji.setUpdatedBy(user.getUserId()); ji.setUpdatedDate(Util.getCurrentTimestamp()); ji.setJobStatus((JobStatus) jobDao.findFirstByProperty("JobStatus", "jobStatusId", JobStatus.KEY_INITIALZING) ); ji.setStartTime(Util.getCurrentTimestamp()); ji.setJob(job); Boolean created = jobDao.saveHibernateEntity(ji); if (created) { String className = job.getJobType().getJavaClass(); Class<?> c = Class.forName(className); Constructor<?> cons = c.getConstructor(JobDAO.class,CustomUserDetails.class,JobInstance.class,Map.class); BaseJobImpl baseJob = (BaseJobImpl) cons.newInstance(jobDao,user,ji,customParams); baseJob.start(); ji.setUpdatedDate(Util.getCurrentTimestamp()); ji.setJobStatus((JobStatus) jobDao.findFirstByProperty("JobStatus", "jobStatusId", JobStatus.KEY_IN_PROCESS) ); jobDao.updateHibernateEntity(ji); StringBuffer successMessage = new StringBuffer(); successMessage.append("Job '").append(jobName).append("' has been started. "); successMessage.append("An email will be sent to '").append(user.getUsername()).append("' when the job is complete. "); String url = baseJob.generateCheckBackURL(); successMessage.append("You can also check the detailed status here: \"").append(url).append("\">").append(url).append(""); response.addInfo(successMessage.toString()); response.setWorked(true); } else { response.addError("Unable to create JobInstance for Job name '"+jobName+"'"); response.setWorked(false); } } } catch (Exception e) { String message = "Unable to runJob. Please contact support"; logger.error(message,e); response.addError(message); response.setWorked(false); } return response; } } public class ThingBulkUpload extends BaseJobImpl { public static final String JOB_NAME = "Thing Bulk Upload"; public static final String KEY_FILE = "file"; public ThingBulkUpload(final JobDAO jobDAO, final CustomUserDetails user, final JobInstance jobInstance, final Map<String,Object> customParams) { super(jobDAO,user,jobInstance,customParams); } @Override public void run() { SaveResponse response = new SaveResponse(); response.setWorked(false); try { final InputStream inputStream = (InputStream) getCustomParam(KEY_FILE); if(inputStream == null) { response.addError("Unable to run ThingBulkUpload; file is NULL"); } else { final AnotherThingImporter cri = new AnotherThingImporter(customParams); cri.changeFileStream(inputStream); response = cri.importThingData(user); } } catch (final Exception e) { final String message = "Unable to finish ThingBulkUpload"; logger.error(message,e); response.addError(message + ": " + e.getMessage()); } finally { finalizeJob(response); } } } public class AnotherThingImporter { // Op: Instantiated this way, even though the impls are annotated with Spring's @Repository. private final LocationDAO locationDAO = new LocationDAOImpl(); private final ContactDAO contactDAO = new ContactDAOImpl(); private final EntityDAO entityDAO = new EntityDAOImpl(); private final BaseHibernateDAO baseDAO = new BaseHibernateDAOImpl(); // Op: snip a few dozen more DAOs private InputStream workbookStream = null; private final Map<String, Object> customParams; public ClientRosterImporter(final Map<String, Object> customParams) { this.customParams = customParams; } public void changeFileStream(final InputStream fileStream) { workbookStream = fileStream; } public SaveResponse importThingData(final CustomUserDetails adminUser) { final SaveResponse response = new SaveResponse(); if (workbookStream == null) { throw new ThreeWonException("MISSING_FILE", "ClientRosterImporter was improperly created. No file found."); } try { final XSSFWorkbook workbook = new XSSFWorkbook(workbookStream); for (int i = 0; i < workbook.getNumberOfSheets(); i++) { final XSSFSheet sheet = workbook.getSheetAt(i); final String sheetName = sheet.getSheetName(); // Op: snip 16 unrelated else ifs... } else if (sheetName.equalsIgnoreCase("History")) { populateHistory(adminUser, response, sheet); } // Op: snip 3 more unrelated else ifs... } } catch (final IOException e) { throw new ThreeWonException("BAD_EXCEL_FILE", "Unable to open excel workbook."); } if (response.getErrors() == null || response.getErrors().size() <= 0) { response.setWorked(true); } return response; } // Op: snip 19 completely unrelated methods private void populateEducationHistory(final CustomUserDetails adminUser, final SaveResponse response, final XSSFSheet sheet) { final ThingDataConverter converter = new ThingDataConverterImpl(entityDAO, locationDAO, contactDAO); converter.convertExcelSheet(adminUser, response, sheet, customParams); } } public class ThingChildAssocConverter extends ThingDataConverter { public void convertExcelSheet(final CustomUserDetails adminUser, final SaveResponse response, final XSSFSheet sheet, final Map<String, Object> customParams) { initialize(customParams); final int rowCount = sheet.getPhysicalNumberOfRows(); Integer numCreated = 0; for (int rowIndex = DEFAULT_HEADER_ROW_COUNT; rowIndex < rowCount; rowIndex++) { final XSSFRow currentRow = sheet.getRow(rowIndex); ... // Op: Null pointer thrown from row.getCell(...) //final String name = df.formatCellValue(currentRow.getCell(COL_INST_NUM)); final String name = getValue(currentRow, COL_INST_NUM); ... // Op: creation of the record here } } protected String getValue(final XSSFRow row, final Integer column) { // Op: We can not assume that any given cell will exist on all spreadsheets try { return df.formatCellValue(row.getCell(column)).trim(); } catch (final Exception e) { // avoid NullPointers by returning "" instead of null return ""; } } }
As opposed to two simple methods that just retrieved the cells, in order, from each specific spreadsheet format.
[Advertisement]
Atalasoft’s imaging SDKs come with APIs & pre-built controls for web viewing, browser scanning, annotating, & OCR/barcode capture. Try it for 30 days with included support.
https://thedailywtf.com/articles/you-absolutely-don-t-need-it
|
Метки: CodeSOD |
CodeSOD: Cases, Cases, Cases |
Paul R. shows us a classic example of the sort of case statement that maybe, you know, never should've been implemented as a case statement:
It is cut and paste to the extreme. Even worse, as fields were added, someone would have to go in and update this block of code. This massive block was replaced with...
var fieldName = reader["TemplateFieldName"].ToString();
theCommands = theCommands.Replace(
fieldName, WashTheValue(reader["FieldValue"].ToString(),
reader["OrderingFieldID"].ToString(),
reader["PriceFormat"].ToString()));
Below, you'll find the original code. Don't sprain your scrolling finger!
switch (reader["TemplateFieldName"].ToString())
{
case "<2yr.Guarantee>":
theCommands = theCommands.Replace("<2yr.Guarantee>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
case "":
theCommands = theCommands.Replace("", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));
break;
default:
break;
}
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: CodeSOD |
CodeSOD: A Bad Route |
Ah, consumer products. Regardless of what the product in question is, therres a certain amount of design that goes into the device. Not design which might make the product more user-friendly, or useful, or in any way better. No, design, which means it looks nicer on the shelf at Target, or Best Buy, or has a better image on its Amazon listing. The manufacturer wants you to buy it, but they dont really care if you use it.
This thinking extends to any software that may be on the device. This is obviously true if its your basic Internet of Garbage device, but its often true of something we depend on far more: consumer grade routers.
Micha Koryak just bought a new router, and the first thing he did was peek through the code on the device. Like most routers, it has a web-based configuration tool, and thus it has a directory called applets which contains JavaScript.
Javascript like this:
function a6(ba) {
if (ba == "0") {
return ad.find("#wireless-channel-auto").text()
} else {
if (ba == "1") {
return "1 - 2.412 GHz"
} else {
if (ba == "2") {
return "2 - 2.417 GHz"
} else {
if (ba == "3") {
return "3 - 2.422 GHz"
} else {
if (ba == "4") {
return "4 - 2.427 GHz"
} else {
if (ba == "5") {
return "5 - 2.432 GHz"
} else {
if (ba == "6") {
return "6 - 2.437 GHz"
} else {
if (ba == "7") {
return "7 - 2.442 GHz"
} else {
if (ba == "8") {
return "8 - 2.447 GHz"
} else {
if (ba == "9") {
return "9 - 2.452 GHz"
} else {
if (ba == "10") {
return "10 - 2.457 GHz"
} else {
if (ba == "11") {
return "11 - 2.462 GHz"
} else {
if (ba == "12") {
return "12 - 2.467 GHz"
} else {
if (ba == "13") {
return "13 - 2.472 GHz"
} else {
if (ba == "14") {
return "14 - 2.484 GHz"
} else {
if (ba == "34") {
return "34 - 5.170 GHz"
} else {
if (ba == "36") {
return "36 - 5.180 GHz"
} else {
if (ba == "38") {
return "38 - 5.190 GHz"
} else {
if (ba == "40") {
return "40 - 5.200 GHz"
} else {
if (ba == "42") {
return "42 - 5.210 GHz"
} else {
if (ba == "44") {
return "44 - 5.220 GHz"
} else {
if (ba == "46") {
return "46 - 5.230 GHz"
} else {
if (ba == "48") {
return "48 - 5.240 GHz"
} else {
if (ba == "52") {
return "52 - 5.260 GHz"
} else {
if (ba == "56") {
return "56 - 5.280 GHz"
} else {
if (ba == "60") {
return "60 - 5.300 GHz"
} else {
if (ba == "64") {
return "64 - 5.320 GHz"
} else {
if (ba == "100") {
return "100 - 5.500 GHz"
} else {
if (ba == "104") {
return "104 - 5.520 GHz"
} else {
if (ba == "108") {
return "108 - 5.540 GHz"
} else {
if (ba == "112") {
return "112 - 5.560 GHz"
} else {
if (ba == "116") {
return "116 - 5.580 GHz"
} else {
if (ba == "120") {
return "120 - 5.600 GHz"
} else {
if (ba == "124") {
return "124 - 5.620 GHz"
} else {
if (ba == "128") {
return "128 - 5.640 GHz"
} else {
if (ba == "132") {
return "132 - 5.660 GHz"
} else {
if (ba == "136") {
return "136 - 5.680 GHz"
} else {
if (ba == "140") {
return "140 - 5.700 GHz"
} else {
if (ba == "149") {
return "149 - 5.745 GHz"
} else {
if (ba == "153") {
return "153 - 5.765 GHz"
} else {
if (ba == "157") {
return "157 - 5.785 GHz"
} else {
if (ba == "161") {
return "161 - 5.805 GHz"
} else {
if (ba == "165") {
return "165 - 5.825 GHz"
} else {
if (ba == "184") {
return "184 - 4.920 GHz"
} else {
if (ba == "188") {
return "188 - 4.940 GHz"
} else {
if (ba == "192") {
return "192 - 4.960 GHz"
} else {
if (ba == "196") {
return "196 - 4.980 GHz"
} else {
return ""
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: CodeSOD |
Error'd: The Journey of a Thousand Miles Begins with a Single Error |
Drew W. writes, "If I'm already at (undefined), why should I pay $389.99 to fly to (undefined)?"
"I'm glad I got this warning! I was planning on going to location near impacted roads," wrote Kelly G.
This submission is different - Peter G. included the perfect caption in the image as a response to Air New Zealand's in-flight survey.
"I have to admit, saving {{slider.total().discount}}% is tempting, but the discounted titles don't seem very interesting," Filippo wrote.
"Yes, YouTube app, I understand that maps without New Zealand exist. I'm not sure what else you're trying to tell me however," Robin S. writes.
Rebecca wrote, "I was asked to look at a user's personal laptop and started with updates. I knew Windows 8 was bad, but that bad?!"
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
https://thedailywtf.com/articles/the-journey-of-a-thousand-miles-begins-with-a-single-error
|
Метки: Error'd |
CodeSOD: Never Bother the Customer |
Matthew H was given a pretty basic task: save some data as a blob. This task was made more complicated by their bosss core philosophy, though.
Never. Bother. The. Customer..
Right, but if the operation fails and we cant continue?
Never. Bother. The. Customer.
Okay, sure, but what if they gave us bad input?
Never. Bother. The. Customer.
Okay, sure, but what if, by hitting okay, were going to format their entire hard drive?
Never. Bother. The. Customer.
As such, for every method that Matthew wrote, he was compelled to write a safe version, like this:
protected void SaveToBlobStorageSafe()
{
try
{
SaveToBlobStorage();
}
catch (Exception ex)
{
}
}
No errors, no matter what the cause, were ever to be allowed to be seen by the user.
|
Метки: CodeSOD |
No Chemistry |
Tyler G.s engagement manager, Sheila, had a new gig for him. The Global Chemical Society, GCS, had their annual conference coming up, and their system for distributing the schedules was a set of USB thumb-drives with self-hosting web apps.
Youll be working with two GCS representatives, Jeff and Graham, Sheila explained. Theyll provide you with last years source code, and the data for this years schedule. Youll need to wire them up.
Later that day, the four of them- Tyler, Sheila, and Jeff and Graham- joined a Skype call. Only the top of Jeffs shiny, bald head could be seen on his webcam, and Graham had joined audio-only.

Sheila managed the introductions. Tyler started the discussion by asking what format they could expect the schedule data to come in.
Jeff shrugged, or at least thats what they guessed from the way the top of his head bobbed. Graham, do you know?
I think it might be XML, Graham replied, his voice muffled with static and saturated with background noise. I cant say for sure. Well send a preliminary data dump first.
The data arrived that afternoon, as a single XML file.
The first time Tyler tried to open it, Notepad++ crashed in protest. After a few attempts, he finally coaxed the editor into letting him see the file. It had no uniform format. Individual fields might be HTML-formatted strings, indecipherable base64-encoded binary blobs (with no indicator as to what data was encoded), and even their plaintext encodings switched from 8-bit to 16-bit arbitrarily.
As soon as Tyler explained to Sheila what a mess the data as, she called GCS reps for another video conferece. Jeffs shiny pate bobbed around as he listened to their complaints. Sheila finally asked, Can you do anything to clean up the data?
Not really, no, Jeff replied. This is how we get the data ourselves.
Absolutely not, Graham concurred.
We did this last year, Jeff replied, and we didnt have any trouble.
For weeks, Tyler worked on an importer for the XML blob. He figured out what the base64-encoded data was (PDF files), why the encoding kept changing (different language encodings), and why some text was HTML-formatted and some wasnt (the entries were copied from email, with some as HTML and some as plaintext).
Jeff and Graham had no interest in the action items assigned no them, and continued to be the largest obstacles to the project. They offered no help, they changed their minds nearly daily, and when Sheila started scheduling daily calls with them, they used those calls as an opportunity to be sarcastic and insult Tyler.
Sheila, who had begun the project in a cheerful manner, started balling her fists during each call with Jeff and Graham, now nicknamed Statler and Waldorf. After one particularly grueling call, she cursed and muttered dark things about How do they get anything done?
After weeks of frustration, pulled hair, and cranky calls, Tylers importer was finished. With a few days to go before the conference, they had just enough time to hand the software off and get the USB sticks loaded.
During that mornings video conference, Jeff and Graham announced that the format had changed to CSV. Sheila, barely keeping her voice level, asked why the format had changed.
Oh, the industry standard changed, Graham said.
And why didnt you tell us?
Jeffs shiny scalp tilted as part of an offscreen shrug. Sorry. Guess we forgot.
The CSV-encoded data, the final and official data-dump for the conference, arrived just one day before the app was due. It came in three files, seemingly split at random, with plenty of repetition between the files. It was all the same, insanely encoded data, just wrapped as CSV rows instead of XML tags.
Tyler crunched his way through an all-nighter. By morning, the importer was finished. He sent the code to GCSs servers, went home, and collapsed.
The coming Sunday, attendees would arrive at the GCS conference. They would be given a USB stick, that they could plug into their laptops. The conference app would work perfectly, taking the fractured, convoluted data, and presenting it as a scrollable, interactive calendar of panels, presentations, and convention hall hours. Some graduate student, a lab assistant to a Nobel lauerate, would open the app and wonder:
This programming thing doesnt seem like a lot of work.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: Feature Articles |
CodeSOD: Gotta Get 'Em All |
LINQ brings functional programming and loads of syntactic sugar to .NET languages. Its a nice feature, although as James points out, it helps if your fellow developers have even the slightest clue about what theyre doing.
// some validation checking
var retrieveDocIdList = this.storedDocumentManager.GetAllForClientNotRetrieved(client.Id).Select(x => x.Id.ToString(CultureInfo.InvariantCulture)).ToList();
retrieveDocIdList.ForEach(id => {
var storedDoc = this.storedDocumentManager.Get(int.Parse(id))
// do some other stuff with the doc
});
James writes:
The code snippet is somewhat paraphrased because the actual code is poorly formatted and full of junk, but this is the main point.
It seems to be a requirement that previous developers leave weird code behind with no documentation or comments explaining what they were thinking at the time.
Well, first, poorly formatted and full of junk is our stock-in-trade, but we do appreciate the focus on the main WTF. Lets see if we can piece together what the developers were thinking.
If youve read an article here before, your eyes almost certainly will catch the x.Id.ToString and the int.Parse(id) calls. Right off the bat, you know somethings fishy. But lets walk through it.
this.storedDocumentManager.GetAllForClientNotRetrieved(client.Id) returns a list of all the documents that have not beeen loaded from the database. Now, by default, this is equivalent to a SELECT *, so instead of getting all that data, they pick off just the IDs as a string in the Select call.
Now, they have a list of IDs of documents that they dont have loaded. So now, they can take each ID, and in a ForEach call… fetch the entire document from the database.
Well, thats what it does, but what were they thinking? We may never know, but at a guess, someone knew that Select star bad, select specific fields, and then they just applied that knowledge without any further thought. The other possibility is that the team of developers wrote individual lines without talking to anyone else, and then just kinda mashed it together without understanding how it worked.
James replaced the entire thing:
foreach (var storedDoc in this.storedDocumentManager.GetAllForClientNotRetrieved(client.Id)) {
//do some other stuff with the doc
}
[Advertisement]
Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.
|
Метки: CodeSOD |
Classic WTF: #include "pascal.h" |
It's Labor Day in the US, where to honor workers, some people get a day off, but retail stores are open with loads of sales. We're reaching back to the old days of 2004 for this one. -- Remy
Ludwig Von Anon sent in some code from the UI component of a large, multi-platform system he has the pleasure of working on. At first glance, the code didn't seem all too bad ...
procedure SelectFontIntoDC(Integer a) begin
declare fonthandle fh;
if (gRedraw is not false) then begin
fh = CreateFontIndirect(gDC);
SelectObject(gDC, fh);
DeleteObject(fh);
end;
end;
Seems fairly normal, right? Certainly nothing that meets our ... standards. Of course, when you factor in the name of the codefile (which ends in ".c") and the header included throughout the entire project ("pascal.h"), I think it becomes pretty apparent that we're entering Whiskey Tango Foxtrot country:
#define procedure void
#define then
#define is
#define not !=
#define begin {
#define end }
Yeeeeeeeee Haw! Sorry, just can't get enough of Mr. Burleson.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
https://thedailywtf.com/articles/classic-wtf-include-pascal-h
|
Метки: Feature Articles |
Error'd: Thresholds Were Made to be Broken |
Dima R. wrote, "Running out of space on this old XP machine. I know, I'll just uninstall TurboTax 2014!"
George wrote, "Encountered this while filling out my Australian tax return via the ATO's website, but it's more like like an ATUH-OH if you ask me!"
"Their motto should be 'We put your health first...and your security last!'" Vladimir B. writes.
"Well, since jeans cover the top of your lap, it's maybe, kind of a laptop," wrote Mike R.
"I guess on the bright side, at least PayPal knows how when and how much I paid to Undefined," wrote Travis M.
"I didn't realize that screaming in my resume was a requirement," Shyam writes.
The Sketch editor worked great! That is, until someone decided not to look at filenames," writes Jeff K.
https://thedailywtf.com/articles/thresholds-were-made-to-be-broken
|
Метки: Error'd |