Error'd: A World Turned Upside Down |
John A. wrote, "Wait, so 'Cancel' is 'Continue' and 'OK' is really 'Cancel'!?"
"Not only that; we are thankful too!" writes Bob S.
"With those NaN folks viewing my profile on Academaia.edu, it's only a matter of time before the world beats a path to my door!" writes Jason K.
Andrea S. wrote, "I'm not sure what fail(ed) but it definitely fail(ed)."
"Never thought I'd say it, but thank goodness for unpatched OS! Now I don't have to pay the parking meter!" writes Juan J.
"Congrats on your new job... Oh wait...what?!" Leslie A. writes.
Tony wrote, "My laptop seems to think it's REALLY good at charging its battery."
[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!
|
Метки: Error'd |
CodeSOD: Switched Over |
Twelve years ago, a company decided they needed a website. They didnt have any web developers, and they didnt want to hire any, so they threw a PHP manual at the new hire who happened to be good with computers, and called it a day.
Ms. Good With Computers actually learned something from the experience, and moved on to a lucrative career in web development. Unfortunately, she left behind the code she learned by doing, and now Bert has been brought in to clean up the code.
Take this block, which translates an airport code into a location name…
switch ($v) {
case "EIN": $ori = "Eindhoven";
break;
case "EIN": $ori = "Eindhoven";
break;
case "EIN": $ori = "Eindhoven";
break;
case "EIN": $ori = "Eindhoven";
break;
case "EIN": $ori = "Eindhoven";
break;
case "EIN": $ori = "Eindhoven";
break;
default: break;
}
switch ($b) {
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
case "WRO": $des = "Wroclaw";
break;
default: break;
}
Theres hundreds of lines of this, following the same pattern- one switch block with the same condition repeated many times for each possible airport code. These blocks dont exist in a function, either- theyre slapped right into the global namespace.
|
Метки: CodeSOD |
Dot-Matrix Ragnarok |
Fresh out of college and out of money, Johan K. started work at Midgard Manufacturing as a junior developer. His supervisor Ragna made it clear: he would only be responsible for coding error handlers.
Our plant equipment is several decades old, she said, and we have to rely on the manufacturer-provided documentation for adequate coverage. To be honest, none of the senior developers want to bother. So instead of bothering one of them, youll be doing it.
Johan didnt have a problem with this. He knew hed have to earn his chops at Midgard. But after he was given the stack of manuals that towered over his monitor, he wondered just how long it would take.
One month later, he had made it through a hundred pages of the first manual. Ragna checked in periodically, more interested in how complete his code was than how quickly he was getting through his list of error conditions.
The manual he was working on was for a steel press. Vintage 1985, the steel presss firmware - using Microsoft Xenix - relied on the flakiest of communication protocols: passing information via temp file. Every night around 2AM, the press would go down for maintenance. A shell script, written by Johan, would read data from the temp file the steel press had created, enter it into a SQL database, then delete the file from disk.
Half the lines of code in Johans script were if/then blocks, one for each condition listed in the manual.
# if the temp file was created successfully
...
# if the local file was written successfully
...
# if the temp file was successfully removed from the firmware
...
That last one got Johan thinking. When has a rm command ever failed silently? Would he really need to check that the file was removed? The conditions for that to happen seemed as impossible as, well, the end of the world. However, as it was listed as an error condition in the manual, he had to put something in.
echo "Ragnarok has come, the Midgard serpent awakes" > /dev/lpr
In this unlikely event, an error would be spit out to the old dot matrix printer in the office, so someone would see it. For good measure, he also had an email sent to all@midgardmanufacturing.se, as well as sending an SMS text. Johan thought that should take care of it.
Several months later, Johan had finished coding the conditions in the first manual. His script had been tested and deployed, and it now monitored the steel press. Things had gone well for a few weeks.
Then, at 3 AM, his phone started buzzing.
The screen filled text messages. Each read the same: Ragnarok has come, the Midgard serpent awakes. His inbox overflowed with a thousand emails, each with the same text as the alert. At first he thought it was a prank by one of the senior developers.
Then he remembered.
He rushed to the office, half-awake. As he entered the unlit office, he heard something tearing and squealing from the other side of the room. After stumbling over some office chairs, he found the source: the dot matrix printer. It had chewed through an entire box of feed paper.
Ragnarok has come, the Midgard serpent awakes
Ragnarok has come, the Midgard serpent awakes
Ragnarok has come, the Midgard serpent awakes
...
Ragna was surprisingly forgiving of Johan. Johan wrote out a proper error message, which would be emailed to only himself and a few other staff, so that his script could fail gracefully.
The senior developers, though, werent so kind. His cubicle walls were papered with sheets of line feed, glued so they couldnt be pulled off, the apocalyptic words smeared in ribbon ink. Someone impersonating Loki from the Marvel movies would randomly message him from an unlisted number. He even found a plush snake wrapped around his computer monitor one morning.
Johan thought it was a good lesson in hubris. He knew it could have been worse: at least it hadnt gone out to all of Midgards customers&
|
Метки: Feature Articles |
CodeSOD: Flubbed Buzz |
Interviewing developers always poses a challenge. You cant rate their skills at writing code without seeing them write code, and most of the code theyve written probably belongs to someone else. Writing anything non-trivial takes time, which both the candidate and the interviewer may not be willing to spend. Even then, its not always representative. And lets not even talk about whiteboard programming.
Douglass company makes a compromise- theyll give a time-boxed programming challenge. A developer is given two hours, access to the Internet, and a moderately complex problem. A smart developer might make some mistakes on the trickier parts of the problems, which is great, because it doesnt fail them- it shows how they think. One candidate, Steve, never quite got that far.
At one point in the process, the code needs to determine if two dates are within 90 days of each other. Even in Java, this is a trivial task, worthy of one line of code. Possibly two, if you want to be super clear:
long days = TimeUnit.MILLISECONDS.toDays(d1.getTime() - d2.getTime());
Steve did this:
public Map computeDiff(Date date1, Date date2) {
long diffInMillies = date2.getTime() - date1.getTime();
List units = new ArrayList(EnumSet.allOf(TimeUnit.class));
Collections.reverse(units);
Map result = new LinkedHashMap();
long milliesRest = diffInMillies;
for ( TimeUnit unit : units ) {
long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
long diffInMilliesForUnit = unit.toMillis(diff);
milliesRest = milliesRest - diffInMilliesForUnit;
result.put(unit,diff);
}
return result;
}
Now, we see the use of the same objects and methods- getTime and TimeUnit, but obviously Steve didnt know anything about them. In fact, I suspect that Steve found this code in a tutorial on Java date times, saw that it calculated the difference in every possible unit, and just said, Yeah, that sounds good.
If that were the case, that would also mean Steve was a terrible researcher, because this was where he spent most of those two hours. For further proof that Steve hadnt a clue, we can also look at how he called this method. Keep in mind the signature of this method- its a Map, leveraging Javas generics system.
Map m = computeDiff(inputRecIn.date,inputRec.date);
Object o = m.get(TimeUnit.DAYS);
long l = Long.parseLong((String)o);
It might be stored that way, but Steve decided to catch the number of days as an Object, and then cast that to a string so that he could parse it back into a Long. Everything about this is wrong.
This is an example of something I think is a true: coding challenges wont help you find good candidates during your interview process, but itll definitely identify the bad ones.
[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.
|
Метки: CodeSOD |
CodeSOD: Classic WTF: Time for a tblHoliday |
It's a holiday in the US today, which tracking the dates on which holidays fall is always a complicated, fraught proposition. Let's dig back into the archives for a classic article which can help us celebrate this holiday. This article originally ran waaaaaay back in 2006. --Remy
For most, the New Year is great occasion: not only is it kicked off with a big bash, but it's so easy to trick yourself in feeling like you have a "clean slate", setting all sorts of great goals and resolutions, and just all-around feeling good. But for some programmers, like Dave Sussman, it's not so joyous of an occasion; each change of the year is like a mini-Y2K. These programmers are the guys who get to maintain systems with comments like ...
//I doubt this script will be in use two years //from now, so this should be fine for now ...
When 2006 hit, Dave got to learn about a database table named tblHoliday. It's hard to say what's more off: the fact that the original programmer had the hindsight to backdate the holidays to 1975, but just couldn't comprehend that the system might last more than four years, or the technique used to store and retrieve whether or not a specific date is a holiday (or, apparently, weekend) ...
SELECT * FROM tblHoliday -- +---------+--------------------------------------------------------------------------+ | intYear | blnaryHoliday | +---------+--------------------------------------------------------------------------+ | ... | ... | +---------+--------------------------------------------------------------------------+ | | NYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNN | | | YYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNY | | 1995 | YYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYY | | | YYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYY | | | YYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYY | | | YNNYYYYYNN | +---------+--------------------------------------------------------------------------+ | | YYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNY | | | YYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYY | | | YYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYY | | 1996 | YYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYY | | | YNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYYNNYYYYY | | | NNYYYYYNNYY | +---------+--------------------------------------------------------------------------+ | ... | ... | +---------+--------------------------------------------------------------------------+
[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!
http://thedailywtf.com/articles/classic-wtf-time-for-a-tblholiday
|
Метки: CodeSOD |
Error'd: The Developer Test |
"Apparently, if AMEX's site knows that you're a developer, it will present a REGEX challenge before allowing you to reset your password," Jim wrote.
Stuart writes, "Wait, I have a network drive!? Cool! I wonder how much space is available? Oh..."
"To you and me, $0.00375 isn't much, but to Western Digital, collecting the exact amount due is a pretty big deal," writes Jonathan.
"The page can say whatever it wants, but, well, here I am anyway," wrote Mark
Andy J. writes, "I don't know what I have just agreed to but at least the paper is now listed as one of my own publications."
"Um, excuse me, but it's not a 'hashtag'," Steve B. wrote, "It's an octothorpe! Or a number sign, or a pig pen..."
[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!
|
Метки: Error'd |
Icon on Fire |
Tim joined a company that provided a SaaS solution for tracking attendance and grades in schools. The job was mostly minor updates to a ColdFusion application, although there was an active project to replace it with something more modern. Tim felt like half of his hiring was based on him knowing when to throw out buzzwords like SPA or REST or Reactive Programming.
Its not the first time, Karmen explained. Shed been with the company for some time. When I joined, they had just upgraded to ColdFusion from a VBA hack on Microsoft Access. Crazy days, back then, when the whole selling service, not software thing was new. Sometimes, I think I was hired because I knew the right buzzwords.
Ostensibly, Karmen and Tim were meant to be focused on the new version of the application, but the ColdFusion version was so old and so poorly maintained that they spent 75% of their time in firefighting mode. The rest of the team had neatly adapted to the culture of just put out the fire, and dont worry about code quality, therell be a new fire tomorrow, which of course only created more fires to put out.
One day, near the end of the month, the webmaster inbox had an alert message from their webhost.
This is to alert you that your account is nearing the data transfer threshold. Your account has transferred 995GB of data during this billing period, with a total account limit of 1,000GB of data allowed. At your pricing tier, overages will be charged at $10/GB.
Wow, what? Tim was pretty shocked. He knew they had a goodly number of schools, and were tracking many thousands of students, but there was no way that the application should be serving up 1TB of data in a month. 95% of the application just was text, and while they did have photographs of every student, those photos were only 9kb after resizing and compressing.
Oh, yeah, Karmen said. I heard about this a few years back. We had to upgrade to the higher plan with our host. Guess theyll probably do that again.
I mean, dont you think this is wrong?
Probably, sure, but… yknow. Not my circus, not my monkeys. Karmen shrugged, and got back to work on a different fire.
Tim fired up the browser debugger and loaded a page in test that was sure to have a lot of pictures, and was definitely the heaviest page. With 50 student images displayed, the payload of the HTML and assets was a whopping 452KB. That was the HTML and assets… except for one file.
The favicon.ico weighed in at 307kb. Apparently, at some point in the past, someone had decided that it needed to look good at any size. Since the ICO format lets you have multiple resolutions of the image stored at different bit-depths and resolutions, they had made sure to include everything up to 256x256 at 32-bits per color. Ironically, the source image had probably been a much smaller resolution, because the 256x256 version showed clear signs of having been upscaled.
Compounding the problem, since once-upon-a-time there had been issues with browsers serving up cached versions of pages, their web server had been configured to disable caching for every file served, guaranteeing that the favicon would be transferred for every request.
307kb wasnt a lot of data, but it was certainly a lot for a favicon. Even at a massive 256x256 resolution, given the design of their icon, he could fit it into a PNG that was bytes in size- and every decent browser supported it. A quick check of their traffic showed that they still had a good number of users on old versions of IE that couldnt support anything but ICO files, so he cut the massive resolutions out of the ICO file, and whipped up a little CFML that would serve the ICO to those users, and everyone else would get the PNG.
That cut their traffic nearly in half, but Tim didnt get much chance to celebrate- there was another fire to put out.
|
Метки: Feature Articles |
CodeSOD: Lucee Execution |
Recently, at my dayjob, I had a burning need to understand how scheduled tasks work. You see, we've recently switched from Adobe Coldfusion to Lucee, and I was shaky on how Adobe did things before, so I wanted a deeper understanding of how the code I was working on would be executed. For the uninitiated, Lucee is an open-source reimplementation of Cold Fusion. And that's not the WTF.
It's open source, I thought to myself. I'll just take a look at the code.
I had one problem. Then I looked at the code. Now I have two problems ... and a headache:
private long calculateNextExecution(long now, boolean notNow) {
long nowTime=util.getMilliSecondsInDay(timeZone,now);
long nowDate=now-nowTime;
// when second or date intervall switch to current date
if(startDate / init calendar
Calendar calendar = JREDateTimeUtil.getThreadCalendar(timeZone);
calendar.setTimeInMillis(startDate+startTime);
long time;
while(true) {
time=getMilliSecondsInDay(calendar);
if(now<=calendar.getTimeInMillis() && time>=startTime) {
// this is used because when cames back sometme to early
if(notNow && (calendar.getTimeInMillis()-now)<1000);
else if(intervall==ScheduleTaskImpl.INTERVAL_EVEREY && time>endTime)
now=nowDate+DAY;
else
break;
}
calendar.add(cIntervall, amount);
}
return calendar.getTimeInMillis();
}
"So okay, if now is before or starting at—hang on, what's calendar again?" I found myself muttering aloud. "Okay, if now is before or equal to the start date plus the start time, and time—which, if I understand that method correctly, is the elapsed time in the current day—is after or equal to the start time ... when is that true exactly? You know what would be nice? Some #%#@$%@ Javadoc!"
This is only one representative method, and yet, there's just so much here. Why an if statement that does nothing, terminating in an easily-overlooked semicolon? Why the misspelling of EVERY? Or "Intervall?" Why are the programmers allergic to spaces? Why can't they name variables worth anything? Do I even really want to know how this works anymore?
If you want to witness the madness for yourself, may I remind you: this code is open source. Have at ye. According to the copyright statement at the top, this code was inherited from the Railo project, so if you're in Switzerland, please be sure to send your hate mail to the right address.
[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 |
Take the Bus |
Rachel started working as a web developer for the local bus company. The job made her feel young, since the buses, the IT infrastructure, and most of their back-office code was older than she was. The bus fare-boxes were cash only, and while you could buy a monthly pass, it was just a little cardboard slip that you showed the driver. Their accounting system ran on a mainframe, their garage management software was a 16-bit DOS application. Email ran on an Exchange 5.5 server.
In charge of all of the computing systems, from the web to DOS, was Virgil, the IT director. Virgil had been hired back when the accounting mainframe was installed, and had nestled into his IT director position like a tick. The bus company, like many such companies in the US, was ostensibly a private company, but chartered and subsidized by the city. This created a system which had all the worst parts of private-sector and public-sector employment merged together, and Virgil was the master of that system.
Rachel getting hired on was one of his rare losses, and he wasnt shy about telling her so.
Ive been doing the web page for years, Virgil said. It has a hit counter, so you can see how many hits it actually gets- maybe 1 or 2 a week. But management says we need to have someone dedicated to the website. He grumbled. Your salary is coming out of my budget, you know.
That website was a FrontPage 2000 site, and the hit-counter was broken in any browser that didnt have ActiveX enabled. Rachel easily proved that there was far more traffic than claimed, not that there was a lot. And why should there be? You couldnt buy a monthly pass online, so the only feature was the ability to download PDFs of the hand-schedules.
With no support, Rachel did her best to push things forward. She redesigned the site to be responsive. She convinced the guy who maintained their bus routes (in a pile of Excel spreadsheets) to give her regular exports of the data, so she could put the schedules online in a usable fashion. Virgil constantly grumbled about wasting money on a website nobody used, but as she made improvements, more people started using it.
Then it was election season. The incumbent mayor had been complaining about the poor service the bus company was offering, the lack of routes, the costs, the schedules. His answer was, cut their funding. Management started talking about belt-tightening, Virgil started dropping hints that Rachel was on the chopping block, and she took the hint and started getting resumes out.
A miracle occurred. The incumbent mayors campaign went off the rails. He got caught siphoning money from the city to pay for private trips. A few local cops mentioned that theyd been called in to cover-up the mayors frequent DUIs. His re-election campaigns finances show strange discrepancies, and money had come in that couldnt be tied back to a legitimate contribution. He tried to get a newly built stadium named after himself, which wasnt illegal, but was in poor taste and was the final straw. He dropped out of the election, paving the way for Mayor Fred to take over.
Mayor Fred was a cool Mayor. He wanted to put in bike lanes. He wanted to be called Mayor Fred. He wanted to make it easier for food trucks to operate in the city. And while he shared his predecessors complaints about the poor service from the bus company, he had a different solution, which he revealed while taking a tour of the bus companys offices.
Im working right now to secure federal grants, private sector funding, to fund a modernization project, Mayor Fred said, grinning from behind a lectern. Did you know were paying more to keep our old buses on the road for five years than it would cost to buy new buses? And thus, Mayor Fred made promises. Promises about new buses, promises about top-flight consultants helping them plan better routes, promises about online functionality.
Promises that made Virgil grumble and whine. Promises that the mayor… actually kept.
New buses started to hit the streets. They had GPS and a radio communication system that gave them up-to-the-second location reporting. Rachel got put in charge of putting that data on the web, with a public API, and tying it to their schedules. A group of consultants swung through to help, and when the dust settled, Rachels title was suddenly senior web developer and she was in charge of a team of 6 people, integrating new functionality to the website.
Virgil made his opinion on this subject clear to her: You are eating into my budget!
Isnt your budget way larger? Rachel asked.
Yes, but theres so much more to spend it on! Were a bus company, we should be focused on getting people moving, not giving them pretty websites with maps that tell them where the buses are! And now theres that new FlashCard project!
FlashCard was a big project that didnt involve Rachel very much. Instead of cash fares and cardboard passes, they were going to get an RFID system. You could fill your card at one of the many kiosks around the city, or even online. Online of course, put it in Rachels domain, but it was mostly a packaged product. Virgil, of all people, had taken over the install and configuration, Rachel just customized the stylesheet so that it looked vaguely like their main site.
Rachel wasnt only an employee of the bus company, she was also a customer. She was one of the first in line to get a FlashCard. For a few weeks, it was the height of convenience. The stop she usually needed had a kiosk, she just waved her card at the farebox and paid. And then, one day, when her card was mostly empty and she wasnt anywhere near a kiosk, she decided to try filling her card online.
Thank you for your purchase. Your transaction will be processed within 72 hours.
That was a puzzle. The kiosks completed the transaction instantly. Why on Earth would a website take 3 days to do the same thing? Rachel became more annoyed when she realized she didnt have enough on her card to catch the bus, and she needed to trudge a few blocks out of her way to refill the card. Thats when it started raining. And then she missed her bus, and had to wait 30 minutes for the next one. Which is when the rain escalated to a downpour. Which made the next bus 20 minutes late.
Wet, cold, and angry, Rachel resolved to figure out what the heck was going on. When she confronted Virgil about it, he said, Thats just how it works. Ive got somebody working full time on keeping that system running, and thats the best they can do.
Somebody working full time? Who? What? Do you need help? Ive done ecommerce before, I can-
Oh no, youve already got your little website thing, Virgil said. Im not going to let you try and stage a coup over this.
With an invitation like that, Rachel decided to figure out what was going on. It wasnt hard to get into the administration features of the FlashCard website. From there, it was easy to see the status of the ecommerce plugin for processing transactions: Not installed. In fact, there was no sign at all that the system could even process transactions at all.
The only hint that Rachel caught was the configuration of the log files. They were getting dumped to /dev/lp1. A printer. Next came a game of hide-and-seek- the server running the FlashCard software wasnt in their tiny data-center, which meant she had to infer its location based on which routers were between her and it. It took a few days of poking around their offices, but she eventually found it in the basement, in an office.
In that office was one man with coke-bottle glasses, an antique continuous feed printer, a red document shredder, and a FlashCard kiosk running in diagnostic mode. Um… can I help you? the man asked.
Maybe? Im trying to track down how were processing credit card transactions for the FlashCard system?
The printer coughed to life, spilling out a new line. Well, youre just in time then. Heres the process. He adjusted his glasses and peered at the output from the printer:
TRANSACTION CONFIRMED: f6ba779d22d5;4012888888881881;$25.00
The man then kicked his rolly-chair over to the kiosk. The first number was the FlashCard the transaction was for, the second was the credit card number, and the third was the amount. He punched those into the kiosks keypad, and then hit enter.
When it gets busy, I get real backed up, he confessed. But its quiet right now.
Rachel tracked down Virgil, and demanded to know what he thought he was doing.
What? Its not like anybody wants to use a website to buy things, Virgil said. And if we bought the ecommerce module, the vendor would have charged us $2,000/mo, on top of an additional transaction fee. This is cheaper, and I barely have enough room in my budget as it is!
|
Метки: Feature Articles |
CodeSOD: Hard Reboot |
Every day in IT, each one of us walks the fine line between "brilliant" and "appalling." We come across things that make our jaws drop, and we're not sure whether we're amazed or horrified or both. Here's a PHP sample that Brett P. was lucky—or unlucky—enough to discover:
This comes from circa 2001, back when there were MySQL stability issues on a server. If in response to the end user's request the script couldn't connect to the session database, PHP would shell out to a VB6 .EXE that rebooted the machine. Ta dum! No more connection error!
if (strpos(mysql_error(), "connect to MySQL server on 'localhost' (10061)")) {
// The MySQL Error: Can't connect to MySQL server on 'localhost' (10061)
// means that the MySQL database is not running. This is caused by a failed
// reboot. Since MySQL is not running, it is safe to execute a hard boot.
echo "Currently rebooting the server. Please try again in two minutes.";
flush();
exec("c:\Progra~1\progs\hardboot.exe");
}
That comment block full of flimsy assumptions and unwarranted confidence makes my insides knot up with dread. I'm leaning toward "appalling" on this one. Anyone else?
[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 Maybe Compiler |
"Maybe it it compiled...maybe it didn't. I guess that I have to find out myself from here on out," wrote, Y. Diomidov.
Ken W. writes, "Does buying the 4 year warranty mean Amazon will replace any steaks that don't last?"
"I *KNEW* that I should have gone for the blue one!" Connor C. wrote.
Adam writes, "Today was a bad day to switch from Chrome."
"Looks like my HP printer had been eating paper behind my back," wrote Peter D.
Jeanne P. writes, "Ironically, we came across this while looking for colleges that offer Computer Science or Software Engineering majors. The pie charts show acceptance rates."
|
Метки: Error'd |
The Smell-O-Vision |
Ron used to work for a company which built smell-o-visions. These were customized systems running small form factor Windows PCs that operated smell pumps and fans using USB relays timed to a video to give a so-called 4D Experience. Their product was gimmicky, and thus absolutely loved by marketing groups.
One such marketing group, whose client was a branch of the military, worked with them to create a gimmick to help with recruiting. A smell-o-vision was installed on a trailer and towed around the country, used to convince teenagers to join the service by making them smell fresh-squeezed orange juice while watching a seizure-inducing video with guns. The trailer was staffed by grunts, and these guys cycled through so frequently that they received little or no training on the system.
Hey Ron, Sam, his boss, told him one day. The recruiter is having a ton of trouble with their system and I need you to go on-site and take a look.
Going on-site was the only option. The recruiters system was not on the Internet so remote diagnosis was impossible. And so he soon found himself cooking in the hot desert sun on a base in the Southwest, looking at a small LCD screen on a 1U pull-out tray accessible through an access panel in the trailer.
This is what it always does, said the grunt assigned to work with him. It always says its corrupted and the 4D stuff doesnt work. Rebooting doesnt fix it.
Ron looked at the screen as the outdated Windows XP booted up and watched it flash an error stating Windows was not properly shut down before beginning a long filesystem scan and repair and then using System Restore to return to an earlier checkpoint. A checkpoint created before the presentation software was installed&
Ron shook his head and started the Help Desk 101 questions. Do you shut down the system when youre packing up?
Oh, we just turn the generator off, the grunt answered. That shuts everything down.
Ron mentally facepalmed. You need to properly shut down the system before killing power or this will happen again. He went inside the trailer and showed them a power button on the control panel. The button was just wired to the power switch header on the PCs motherboard and acted exactly like any computer cases power button. Pressing it briefly tells the operating system to shut itself down. Just press this button and it will shut itself down in a minute or two.
Okay, thats simple enough, the grunt said.
Then Ron spent the day re-installing and configuring their system by downloading all the software over his phones mobile hotspot to his laptop, then transferring it via USB stick. Eventually he had it back up and running. He made sure to stress how important it was to shut down the system, and on a whim left them a DVD with all the software so he could talk someone through the process over the phone if it happened again.
He returned home. And two weeks later, it happened again. He spent three days on the phone talking to a different grunt and walking him through restoring the system. Again he emphasized the importance of shutting down the system with the power button before killing power, but this grunt explained he did that. Ron was confused, but finished the support call.
Just a few days later, they called again. He talked to yet another grunt, asked them how shutdown was handled, and he explained he pressed the button until it shut down. His boss decided to send Ron on-site again, and he repaired the system. It was much faster this time since he had a DVD with everything he needed on it, only taking most of a morning. When he was done, he tested the power button. It shut down the system properly.
Show me how you get ready for a presentation, he asked. From setup once youre on-site, to shutdown.
The pair of grunts assigned to himtwo more hed never worked with beforespent an hour walking through the process. When they got to the end, Ron reminded him to shut down the system.
And the grunt did so. By pressing and holding the power button for about five seconds. Which killed power to the PC without properly shutting down the operating system.
He mentally facepalmed again. No, you cant press and hold. Just tap the button. It will eventually shut down. He was getting fast at restoring the system and spent that afternoon correcting it all. This time he took a System Restore snapshot once everything was in place, and taped a hand-written note on the control panel saying DO NOT HOLD THIS BUTTON TO TURN OFF THE MACHINE. DO NOT SHUT OFF THE GENERATOR WITHOUT FIRST TURNING THE SYSTEM OFF PROPERLY.
He returned home. And a couple weeks later, they called again. He was unable to fix it over the phone and was sent on-site yet again. This time the filesystem was too corrupted to repair and he had to set everything up from scratch. Upon querying the new grunts he discovered they ignored the note and were still holding the power button to kill the system.
This continued for a couple more months. The client refused to shut down the system properly and was constantly causing severe filesystem corruption or even killing hard disks. Each time the client called, getting angrier and angrier. It says there is no OS! I thought you fixed this bug!! Each time the problems were caused by operator error.
During a meeting with his boss Sam, Ron explained all the issues and how much of his time it was taking, and while brainstorming a solution Ron pitched a new idea. What if we modify the custom power button? Alter it to only send a pulse, instead of a constant closed signal, so its impossible to hold it down?
Figure it out and do it, Sam ordered. These guys are idiots and wont do things right. Theyre killing us on support time, we have to fix this or fire the client. How hard is it to shut this thing down properly?
So, being a software engineer, Ron devised a clever solution based on an Arduino that sampled the power buttons state and sent pulses to the motherboards power button header. It passed all his testing and he went on-site to install it. And finally the support calls ceased completely. This unit was the only one that received the update since none of their other clients had issues with operator error.
With the issue solved, Ron decided to take some badly-needed vacation to attend a family reunion in North Carolina and tried to stay off the grid. Meanwhile, Sam took a demo unit to an expo in London so visitors could smell what it was like to go skiiing.
During his vacation, Ron received a phone call from Sam in the middle of the night. Being on vacation and trying to stay offline, he ignored it. But the phone rang in quick succession several more times and he finally answered.
Ron! Sorry to wake you, but our demo unit quit working and I need your help!
Ron grunted. Its one AM here&
I know but I need to get this back up before the conference starts this morning!
Okay, he said with a sigh. Whats it doing?
Sam proceeded to describe a series of error screens over the phone. It stated that Windows was not shut down properly, followed by a long filesystem scan, followed by an error that critical system files were corrupted and Windows could not boot.
Ron facepalmed for real this time.
|
Метки: Feature Articles |
Bring Your Own Code: Your Private Foursome |
Last week, I shared some code that, while imperfect, wasnt that bad. I then issued a challenge: make it worse. Or better, if you really want. As many comments noted: one case covers only the first iteration of the loop, and one case only covers the last iteration of the loop. You could easily pull those out of the loop, and not need a for-case at all. Others noticed that this pattern looked like odd slices out of an identity matrix.
With that in mind, we got a few numpy, Matlab, or MatrixUtils based solutions generally were the best solutions to the problem: generate an identity matrix and take slices out of it. This is reasonable and fine. It makes perfect sense. Lets see if we can avoid making sense.
Ill start with Abner Qians Ruby solution.
module MagicalArrayGenerator
def magical_array_generator
main_array = []
self.times do |i|
inner_array = []
self.times do |j|
i == j ? inner_array << 1 : inner_array << 0
end
main_array << inner_array
end
e_1 = []
n_1 = []
e_n = []
n_n = []
self.times do |i|
e_1 << [main_array[i].first]
e_n << [main_array[i].last]
n_1 << main_array[i][1..-1]
n_n << main_array[i][0..-2]
end
[e_1, n_1, e_n, n_n]
end
end
class Integer
include MagicalArrayGenerator
end
e_1, n_1, e_n, n_n = 4.magical_array_generator
At its core, this is simply an implementation that generates an identity matrix and slices it up. The actual implementation, however, is a pitch-perfect parody of Ruby development: Theres no problem that cant be solved by monkey-patching a method into a built-in type. Thats what happens here- the include statment injects this method into the build-in Integer data-type, meaning you can call 4.magical_array_generator and get your arrays. Abner also points out that Ruby uses 62-bit integers, just in case you want some 4611686018427387903 by 4611686018427387904 arrays.
Several folks looked at the idea of taking slices, and said, Gee, I bet you I could do this with pointers in C. My personal favorite in that category would have to be Ron Ps approach.
#include
int main( int argc, char **argv)
{
int *e_1 = 0;
int *e_n = 0;
int **n_1 = 0;
int **n_n = 0;
int *fugly = 0;
int i,j;
if ( argc != 2 ) return 1;
int n = atoi(argv[1]);
fugly = calloc( n*(n+1),sizeof(int));
n_1 = calloc(n,sizeof(int *));
n_n = calloc(n,sizeof(int *));
for ( i = 0, j=n; i < n; ++i, j+=n+1 )
{
fugly[j]=1;
n_1[i]=fugly+n*i;
n_n[i]=n_1[i]+n;
}
e_1 = fugly+n;
e_n = fugly+1;
printf( "e_1\n" );
for ( i = 0; i < n; ++i ) {
printf( " %d\n", e_1[i]);
}
printf( "\ne_n\n" );
for ( i = 0; i < n; ++i ) {
printf( " %d\n", e_n[i]);
}
printf( "\nn_1\n" );
for ( i = 0; i < n; ++i ) {
printf( " " );
for ( j = 0; j < n-1; ++j ) {
printf("%d ", n_1[i][j]);
}
printf("\n" );
}
printf( "\nn_n\n" );
for ( i = 0; i < n; ++i ) {
printf( " " );
for ( j = 0; j < n-1; ++j ) {
printf("%d ", n_n[i][j]);
}
printf("\n" );
}
return 0;
}
Now, Martin Scolding gets bonus points for two reasons: first, he uses one of the worst languages in the world (not designed as an esolang), and second, this language doesnt technically support multi-dimensional arrays. I speak, of course, of PL/SQL. Note the use of substrings to figure out what number to put in each position of the array.
DECLARE
TYPE data_t IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
TYPE array_t IS TABLE OF data_t INDEX BY PLS_INTEGER;
e_1 array_t;
e_n array_t;
n_1 array_t;
n_n array_t;
l_array_size INTEGER := 0;
PROCEDURE gen_arrays(n INTEGER, p_e_1 IN OUT array_t, p_e_n IN OUT array_t, p_n_1 IN OUT array_t, p_n_n IN OUT array_t)
--' Generate 4 Arrays of the form (example n=4)
--
-- ' | 1 | | 0 0 0 |
-- ' e_1 = | 0 | n_1 = | 1 0 0 |
-- ' | 0 | | 0 1 0 |
-- ' | 0 | | 0 0 1 |
-- '
-- ' | 0 | | 1 0 0 |
-- ' e_n = | 0 | n_n = | 0 1 0 |
-- ' | 0 | | 0 0 1 |
-- ' | 1 | | 0 0 0 |
--
IS
l_n_string LONG := RPAD('1',n+1,'0');
BEGIN
For i in 1..n Loop
p_e_1(i)(1) := TO_NUMBER(SUBSTR(l_n_string, 1, 1));
p_e_n(i)(1) := TO_NUMBER(SUBSTR(l_n_string, n, 1));
For j in 1..n-1 Loop
p_n_1(i)(j) := TO_NUMBER(SUBSTR(l_n_string, j+1, 1));
p_n_n(i)(j) := TO_NUMBER(SUBSTR(l_n_string, j, 1));
End Loop;
l_n_string := LPAD(SUBSTR(l_n_string, 1, n), n+1, '0');
End Loop;
END;
BEGIN
l_array_size := &inp_array;
gen_arrays(l_array_size, e_1, e_n, n_1, n_n);
--==========================================================================
-- DISPLAY RESULTS
--==========================================================================
DBMS_OUTPUT.PUT_LINE('e_1 = ');
For i in 1..l_array_size Loop
DBMS_OUTPUT.PUT_LINE(' | ' || e_1(i)(1) || ' |');
End Loop;
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('e_n = ');
For i in 1..l_array_size Loop
DBMS_OUTPUT.PUT_LINE(' | ' || e_n(i)(1) || ' |');
End Loop;
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('n_1 = ');
For i in 1..l_array_size Loop
DBMS_OUTPUT.PUT(' | ');
For j in 1..l_array_size-1 Loop
DBMS_OUTPUT.PUT(n_1(i)(j) || ' ');
End Loop;
DBMS_OUTPUT.PUT('|');
DBMS_OUTPUT.NEW_LINE;
End Loop;
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('n_n = ');
For i in 1..l_array_size Loop
DBMS_OUTPUT.PUT(' | ');
For j in 1..l_array_size-1 Loop
DBMS_OUTPUT.PUT(n_n(i)(j) || ' ');
End Loop;
DBMS_OUTPUT.PUT('|');
DBMS_OUTPUT.NEW_LINE;
End Loop;
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------');
--==========================================================================
--
--==========================================================================
END;
/
Finally, though, I have to give a little space to Airdrik. While the code may contain some errors, it is in Visual Basic, as was the original solution, and it knows that recursion makes everything better.
Public Sub GenerateIdentitySquare(ByVal n As Long, ByRef sq As Variant, ByVal i As Long, ByVal j As Long)
Select Case j
Case i:
sq(i, j) = #1
If i < n Then
GenerateIdentitySquare(n, sq, i, j+1)
End If
Case n:
sq(i, j) = #0
GenerateIdentitySquare(n, sq, i+1, 1)
Case Else:
sq(i, j) = #0
GenerateIdentitySquare(n, sq, i, j+1)
End Select
End Sub
Public Sub CopyRowValues(ByVal n As Long, ByRef sq As Variant, ByRef e As Variant, ByVal sq_i As Long, ByVal e_i As Long, ByVal j As Long)
e(e_i, j) = sq(sq_i, j)
if j < n Then
CopyRowValues(n, sq, e, sq_i, e_i, j+1)
End If
End Sub
Public Sub CopyRows(ByVal n As Long, ByRef sq As Variant, ByRef e_1 As Variant, ByRef e_n As Variant, ByRef n_1 As Variant, ByRef n_n As Variant, ByVal i As Long)
Select Case i
Case 1:
CopyRowValues(n, sq, e_1, i, 1, 1)
CopyRowValues(n, sq, n_n, i, i, 1)
CopyRows(n, sq, e_1, e_n, n_1, n_n, i+1)
Case n:
CopyRowValues(n, sq, n_1, i, i-1, 1)
CopyRowValues(n, sq, n_n, i, i, 1)
Case Else:
CopyRowValues(n, sq, n_1, i, i-1, 1)
CopyRowValues(n, sq, e_n, i, 1, 1)
CopyRows(n, sq, e_1, e_n, n_1, n_n, i+1)
End Select
End Sub
Public Sub DefineProjectionArrays(ByVal n As Long, ByRef e_1 As Variant, ByRef e_n As Variant, ByRef n_1 As Variant, ByRef n_n As Variant)
Dim i As Long, j As Long
' Generate 4 Arrays of the form (example n=4)
' | 1 | | 0 0 0 |
' e_1 = | 0 | n_1 = | 1 0 0 |
' | 0 | | 0 1 0 |
' | 0 | | 0 0 1 |
'
' | 0 | | 1 0 0 |
' e_n = | 0 | n_n = | 0 1 0 |
' | 0 | | 0 0 1 |
' | 1 | | 0 0 0 |
Dim sq(n, n) As Variant
GenerateIdentitySquare(n, sq, 1, 1)
ReDim e_1(n, 1)
ReDim e_n(n, 1)
ReDim n_1(n, n - 1)
ReDim n_n(n, n - 1)
CopyRows(n, sq, e_1, e_n, n_1, n_n, 1)
End Sub
Functional programming is always the best approach, obviously.
[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!
|
Метки: Bring Your Own Code |
The New Manager |
She'd resisted the call for years. As a senior developer, Makoto knew how the story ended: one day, she'd be drafted into the ranks of the manager, forswearing her true love webdev. She knew she'd eventually succumb, but she'd expected to hold out for a few years before she had to decide if she were willing to change jobs to avoid management.
But when her boss was sacked unexpectedly, mere weeks after the most senior dev quit, she looked around and realized she was holding the short straw. She was the most senior. Even if she didn't put in for the job, she'd be drafted into acting as manager while they filled the position.
This is the story of her first day on the job.
Makoto spent the weekend pulling together a document for their external contractors, who'd been plaguing the old boss with questions night and day— in Spanish, no less. Makoto made sure to document as clearly as she could, but the docs had to be in English; she'd taken Japanese in high school for an easy A. She sent it over first thing Monday morning, hoping to have bought herself a couple of days to wrap up her own projects before the deluge began in earnest.
It seemed at first to be working, but perhaps it just took time for them to translate the change announcement for the team. Just before noon, she received an instant message.
Well, I can just point them to the right page and go to lunch anyway, she thought, bracing herself.
Emilio: I am having error in application.
Makoto: What error are you having?
A minute passed, then another. She was tempted to go to lunch, but the message client kept taunting her, assuring her that Emilio was typing. Surely his question was just long and complicated. She should give him the benefit of the doubt, right?
Emilio: error i am having is: File path is too long
Makoto winced. Oh, that bug ... She'd been trying to get rid of the dependencies with the long path names for ages, but for the moment, you had to install at the root of C in order to avoid hitting the Windows character limits.
But I documented that. In bold. In three places!
Makoto: Did you clone the repository to a folder in the root of a drive? As noted in the documentation there are paths contained within that will exceed the windows maximum path length otherwise
Emilio: No i cloned it to C:\Program Files\Intelligent Communications Inc\Clients\Anonymized Company Name\Padding for length\
Makoto's head hit the desk. She didn't even look up as her fingers flew across the keys. I'll bet he didn't turn on nuget package restore, she thought, or configure IIS correctly.
Makoto: please clone the repository as indicated in the provided documentation, Additionally take careful note of the documented steps required to build the Visual Studio Solution for the first time, as the solution will not build successfully otherwise
Emilio: Yes.
Whatever that means. Makoto sighed. Whatever, I'm out, lunchtime.
Two hours later she was back at her desk, belly full, working away happily at her next feature, when the message bar blinked again.
Dammit!
Emilio: I am having error building application.
Makoto: Have you followed the documentation provided to you? Have you made sure to follow the "first time build" section?
Emilio: yes.
Makoto: And has that resolved your issue?
Emilio: Yes. I am having error building application
Makoto: And what error are you having?
Emilio: Yes. I am having error building application.
"Oh piss off," she said aloud, safe in the knowledge that he was located thousands of miles from her office and thus could not hear her.
"That bad?" asked her next-door neighbor, Mike, with a sympathetic smile.
"He'll figure it out, or he won't," she replied grimly. "I can't hold his hand through every little step. When he figures out his question, I'll be happy to answer him."
And, a few minutes later, it seemed he did figure it out:
Emilio: I am having error with namespaces relating to the nuget package. I have not yet performed nuget package restore
The sound of repeated thumps sent Mike scurrying back across the little hallway into Makoto's cube. He took one look at her screen, winced, and went to inform the rest of the team that they'd be taking Makoto out for a beer later to "celebrate her first day as acting manager." That cheered her enough to answer, at least.
Makoto: Please perform the steps indicated in the documentation for first time builds of the solution in order to resolve your error building the application.
Emilio: i will attempt this fix.
Ten minutes passed: just long enough for her to get back to work, but not so long she'd gotten back into flow before her IM lit up again.
Emilio: I am no longer having error build application.
"Halle-frickin-lujah", she muttered, closing the chat window and promptly resolving to forget all about Emilio ... for now.
|
Метки: Feature Articles |
CodeSOD: Documented Concerns |
Theres a lot of debate about how much a developer should rely on comments. Clear code should, well, be clear, and thus not need comments. On the other hand, code thats clear the minute you write it might not be as clear six months later when you forget what it was for. On the other, other hand, sometimes a crime has been committed and we need the comments for a confession.
Austin S confesses his crime.
private static readonly HtmlElementFlag brokenFormFlag;
private static readonly AtomicInteger currentConfiguredVersion = (AtomicInteger)HTML_PROCESSING_VERSION;
private static readonly ReaderWriterLockSlim configLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
static HtmlLogic()
{
brokenFormFlag = HtmlNode.ElementsFlags["form"];
//fix stupidity
ConfigureFor(HTML_PROCESSING_VERSION);
}
private static void ConfigureFor(int version)
{
if (version >= 8)
{
//form elements are NOT EMPTY!!!!
HtmlNode.ElementsFlags.Remove("form");
}
else
{
//Need to handle broken things properly...
HtmlNode.ElementsFlags["form"] = brokenFormFlag;
}
currentConfiguredVersion.Value = version;
}
///
/// A horrible abomination you need to call whenever you want
/// HtmlAgilityPack to load html or set inner html without breaking
/// things... See top of method for reasons.
///
/// Action to perform while in the version lock
/// Version to lock for
private static void ExecuteWithVersion(Action action, int version)
{
// (Note: you should only need to use this when importing/parsing
// html.I do not believe that you need it when exporting html)
/** Comment author = Austin S. Using CDATA elements to keep
* the IDE sane.
*
* So, you may ask, "Why do we have this unholy mother of
* abominations in our code?" That is an excellent question, allow
* me to explain why. To ensure that both the Java and C# versions
* handle html text the same despite using different html dom
* libraries, we now sanitize the initial html with HtmlTidy. This
* results in both libraries being handed the same (except for the
* "generator" meta attribute that we don't care about) VALID
* html that contains NO ERRORS.
* Ever since version 0 (with BoolOption3 set
* to true I think), we used the HtmlAgilityPack library to parse
* the html we are reading and save it out. Ever since then, it
* has had a certain bug. Allow us to consider the following
* fragment of html (sans the CDATA wrapper):
* "What is so special about this fragment?" you ask. Simple, it
* has a form element. When HtmlAgilityPack parses this fragment,
* we get something like this (comments from me):
* As you can see, is interpreted as text.
* This means that [PRODUCT_NAME] WILL NOT TAG IT AWAY and WILL BE
* VISIBLE TO THE USER FOR TRANSLATION. The Java library does not
* have this issue. The simplest solution to this problem is to
* not have the Java version support html, which is sheer lunacy
* and is not permitted for a number of reasons, such as "Sorry,
* you need to use the Windows version to translate any html."
* Luckily, this can be fixed by modifying a static variable
* in the library like so:
* .Remove("form");
*
* But, as a comment on the StackOverflow answer I got this from
* (http://stackoverflow.com/a/4237224/1366594) mentions, this
* is a breaking change, and the variable is STATIC. If
* you don't know what that means, it means that this setting will
* be read on all threads, regardless of their origin. This
* wouldn't be an issue if it weren't for the fact that we need to
* be able to do the following two things at the same time:
* 1. Keep the code backwards compatible so users can save out old
* Files.
* 2. Support concurrent execution since the user may be saving out
* more than one file at a time and/or the File Handler that
* calls this logic will be doing so on multiple threads.
* It wouldn't be so complex if we only had to handle one of these.
* Our second "simple" fix would be to drop support for one of
* those two things, but we can't drop backwards compatibility
* support in the C# version because that would be stupid and we
* would have angry customers, and we can't drop support for
* concurrent saving since that is also utter lunacy (try saving
* out 100 html files at once...)
* So, we need to move to our next approach, which is this
* abomination. Luckily, I only think we need to do this when
* parsing html. We create a method that wraps all html "parsing"
* calls so we can ensure that the html is parsed with the correct
* settings. Then we have this issue: concurrency. To fix this
* issue, we use an (since I am more
* used to that than using a volatile int that is changed via
* calls to Interlocked) to keep track of the current configured
* version, and a to make sure
* we don't try to run logic for an old version at the same time
* we are running logic for a new version. The new versions use
* the "Read" lock, and the old versions use the "Write" lock.
* This permits us to execute multiple actions with the "current"
* configuration, but has the downside of only letting one action
* with the old versions run at a time. The best way to work
* around this is to implement some sort of concurrent multi lock
* thing that only permits locks of the same key to run at the same
* time, but I haven't found any such thing, and creating our own
* will surely end with someone going mad.
* So now we need to pass in a version number with any call that
* parses html, so are we done, right? WRONG!
* Recently I implemented some version checking on saving out so
* we don't try to save any documents that are too "new", as in
* the user hasn't updated their copy of PRODUCT_NAME and try to save
* out a file they got from a co-worker who did update their copy.
* If we allowed them to do so, the result would likely be invalid
* output, and would result in their customers being unhappy with
* the result since it is useless. If the customer of our customer
* does not catch this before deploying the translation into the
* wild, it would make them look like a fool, so we cannot allow it.
* We store the opening code's primary version in IntOption1 and
* the secondary version (usually the html opener's version) in
* IntOption2 if applicable. We would rename these variables,
* but some users insist on using OLD_PRODUCT_NAME (which is no longer
* receiving updates and also doesn't have any version checking
* on saving out). This is a pain, but there currently isn't much
* that can be done about it, so I digress.
* Due to this stupid breaking change thing, EVERY call to parse
* some html into a or
* a needs to be wrapped with this method
* ( ) with an int
* version passed into it. That version number needs to be stored
* somewhere and is usually stored in IntOption2 (or IntOption1 if
* this was an html file we opened). Then we encounter a new issue.
* The new issue is that the file adapters for .po and .properties
* use some html logic and use IntOption2 for other things, so I
* had to increment the main version numbers on them and move
* those values to IntOption3. Finally, at the end of this method
* ( ) if the current
* settings are not set to the current version and no other threads
* still want to use the old version, we set the config back to
* the current version because we all know that some poor sap will
* forget to wrap his html parsing call in this method, or we might
* do html parsing elsewhere where we cannot reach this method.
* Hopefully, we do not need to do any more insanity...
*/
bool currentVer = version >= 8;
try
{
if (currentVer)
{
configLock.EnterReadLock();
}
else
{
//sadly, this will make it so old html files can only be
//"saved" one at a time, but there isn't much that can
//be done about that without breaking out evil voodo.
configLock.EnterWriteLock();
}
if (currentConfiguredVersion.Value != version)
{
//we need to make sure only one thread makes changes
lock (configLock)
{
if (currentConfiguredVersion.Value != version)
{
ConfigureFor(version);
}
}
}
action();
}
finally
{
if (currentVer)
{
configLock.ExitReadLock();
}
else
{
configLock.ExitWriteLock();
if (configLock.CurrentReadCount < 1 &&
configLock.WaitingReadCount < 1 &&
configLock.WaitingWriteCount < 1)
{
try
{
//reset config
configLock.EnterWriteLock();
lock (configLock)
{
if (currentConfiguredVersion.Value !=
HTML_PROCESSING_VERSION)
{
ConfigureFor(HTML_PROCESSING_VERSION);
}
}
}
finally
{
configLock.ExitWriteLock();
}
}
}
}
}
Honestly, saying much more would be gilding the lily.
[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: Just Buttons |
"What do you think the buttons do? If you thought the dialog was trying to help you log in or give an opportunity to send them an e-mail, instant message, or tweet pointing out how the buttons don't do anything, you might be mistaken," writes Alex M., "
Robert wrote, "This appeared after attempting to clean up a working copy. Apparently, I'm expected to do the same thing again (and again, and again, and AGAIN...)and expect a different result."
"I'm not sure that I can wait another 90 days for April's caffeine supply," writes Martin R.
"I was innocently researching time travel when this happened," wrote Bruce R.
Stephen E. wrote, "I was trying to figure out the order I needed to do my cross product in. I'm not quite sure how that's related to constipation?"
"According to Microsoft, MsoTriState is a 'tri-state Boolean' that apparently has 5 possible values," writes Mark, "But that's OK since only two of them are supported.
Maarten writes, "After installing the latest version of Visual Studio Community Edition, I was excited to give it a try. Unfortunately, after pressing the Launch button I received this instead." At the end of the installation, after pressing the launch button, this error dialog shows up."
[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!
|
Метки: Error'd |
A Naughty Bot |
As many of you know, outside of being a writer, I also work on open-source projects. The most famous of these is Sockbot, a chatbot platform that interfaces with various forum and message clients. If you're reading this, my boss didn't object to pointing out that my work has never made this particular mistake—but maybe we'd be more famous if we had.
This particular chatbot was designed for internal use. The company, like many others, had moved to Slack as an IM program for their development teams. Like every other team that found themselves with a slack, the developers quickly set about programming bots to interact with the platform and assist with common tasks like linking to an issue in the company Jira, pushing out a docker container to the QA environment, and ordering lunch.
Today's submitter, Suzie, wanted to add Google search to her local bot, Alabaster. Often, when people started talking about something, they'd grab the first link off Google and dump it into the chat for context. This way, Alabaster could do that for them. Sure, it wasn't the most useful thing in the world, but it was simple and fun, and really, isn't that why we program in the first place?
Of course, Google puts a rate limit of 100 queries per day on their searching, and you need an API key. Bing, on the other hand, had a much higher limit at the time of 5,000 queries a month, and was much easier to integrate with. So Suzie made the executive decision to settle for Bing and eat the gentle razzing she'd get in response.
If you've never used a chatbot before, there's two ways to design them. The harder but much-nicer-to-use way is to design a natural language processor that can tell when you're talking to the bot and respond accordingly. The easier and thus far more common way is to have a trigger word and a terse command syntax, like !ban user to ban a user from the chat room. Command words are typically prefixed with a bit of punctuation so they can't accidentally be used to start a sentence, too. In the example I gave, the ! informs the bot that you're talking to it, and ban is the command, given the argument user to the command handler.
Alabaster was using !! as his trigger, so Suzie settled on !!bing as the bot command to start a search, passing in the rest of the line. Since she wasn't using Sockbot, she had to handle the line parsing herself. She went the easy way and replaced the first instance of the word "Bing" with empty space before handing the rest of the line to the Bing API.
Or ... she tried to. In reality, she wrote var searchText = message.TargetedText.ToLower().ReplaceFirst("big ", "").Trim();, missing the all-important "n" in "bing".
This wouldn't usually be a big deal. If you start your Google search phrase with the word "google", it's usually ignored while Google searches for the rest of the phrase. Bing, however, is also part of several people's names, such as Bing Crosby, Chandler Bing ... or porn star Carmella Bing, the most searched of the three. Somehow, Suzie had also allowed the searches access to NSFW results. Every time Alabaster was asked to search, it came back with X-rated results about the porn star.
Suzie scrapped the module and started over. This time, she decided Google's rate limit was probably just fine ... just fine indeed.
|
Метки: Feature Articles |
Bring Your Own Code: A Foursome of Arrays |
So, fun fact about myself: I didnt know what the For-Case anti-pattern was until relatively recently, when there were a spate of articles condemning it as an anti-pattern. Im sure Ive probably used it, at some point, but I never knew it by name. Its thought of as a textbook antipattern that generally implies a misunderstanding of for loop, case statements, the problem being solved, or some combination of all three. That said, there are certain problems that might be more clear to solve by using the For-Case. Like GOTO, it might be harmful, but its actual evil exceeds its reputation.
John A had a problem, and most unfortunately for him, this problem involved VBA macros embedded in an Excel spreadsheet. He needed to generate four arrays, that fall into this pattern:
' Generate 4 Arrays of the form (example n=4)
' | 1 | | 0 0 0 |
' e_1 = | 0 | n_1 = | 1 0 0 |
' | 0 | | 0 1 0 |
' | 0 | | 0 0 1 |
'
' | 0 | | 1 0 0 |
' e_n = | 0 | n_n = | 0 1 0 |
' | 0 | | 0 0 1 |
' | 1 | | 0 0 0 |
Now, I dont know what these arrays are for, and Im only guessing at the pattern. John spent hours fiddling with this, and couldnt find a great solution. So he reached for the For-Case. Ill let him explain:
Sure I laughed when others implemented the vile For-Case paradigm. I said this will never happen to me. But today everything changed when I was staring at the screen trying to figure out how to most efficiently and cleanly fill in 4 arrays with the specified pattern. I thought of multiple sequential loops within nested loops and saw that there will always be some repeated statements. It all changed when I decided to set everything to zeros first and then set the non zero entries (I was trying to do all elements at the same time before).
Finally I succumb to the allure of the For-Case paradigm and it materialized in front of me in seconds. My fingers were typing furiously as if they knew when they had to do. Glory at last!. Small, clean and clear. I have betrayed my kind to achieve my most satisfying code fail so far.
Public Sub DefineProjectionArrays(ByVal n As Long, ByRef e_1 As Variant, ByRef e_n As Variant, ByRef n_1 As Variant, ByRef n_n As Variant)
Dim i As Long, j As Long
' Generate 4 Arrays of the form (example n=4)
' | 1 | | 0 0 0 |
' e_1 = | 0 | n_1 = | 1 0 0 |
' | 0 | | 0 1 0 |
' | 0 | | 0 0 1 |
'
' | 0 | | 1 0 0 |
' e_n = | 0 | n_n = | 0 1 0 |
' | 0 | | 0 0 1 |
' | 1 | | 0 0 0 |
' Fill arrays with zeros
e_1 = NewArray(n, 1, 0#): e_n = NewArray(n, 1, 0#)
n_1 = NewArray(n, n - 1, 0#): n_n = NewArray(n, n - 1, 0#)
' Set unit elements according to the pattern above
For i = 1 To n
Select Case i
Case 1: ' first row of e_1 and n_n have values
e_1(i, 1) = 1#
n_n(i, i) = 1#
Case n: ' last row of e_n and n_1 have values
e_n(i, 1) = 1#
n_1(i, i - 1) = 1#
Case Else ' middle rows of n_1 and n_n have values
n_1(i, i - 1) = 1#
n_n(i, i) = 1#
End Select
Next i
End Sub
`
Now, Im gonna go ahead and say it: this doesnt really look all that terrible. Its not a WTF. If anything, its a good example of how a For-Case statement can be used to make clear code. I can come up with minor tweaks to it to make it clearer and cleaner, but as it is, its fine. I wouldnt want to curse the name of the developer who handed me this code.
But John feels bad about it, continuing: And now challenge to the community of coming up with better coding solutions to this.
Well, I welcome your better solutions to this problem, but what Id really love to see is creatively worse solutions. Given the vague requirements (and the singular sample case), whats the worst way you could implement this? In the language of your choosing, whats the dumbest way to accomplish this goal? Bring your own code, either in the comments, or submit your WTF (use the title of this article as your subject line). Well take submissions over the next week, and on 5/18 well run a followup article with the best submissions. The winners get bragging rights, and a pile of WTF stickers and other swag that we can mail cheaply.
[Advertisement]
Otter, ProGet, BuildMaster – robust, powerful, scalable, and reliable additions to your existing DevOps toolchain.
|
Метки: Bring Your Own Code |
Sponsor Post: How to Start Freelance Programming |
By Brenna FloresThis article originally ran on Hired's blog. For more posts like these, and great career insights, join Hired. I chose to run this article here because, well- this is what I do these days. Freelance training, consulting, and development, and I've had the good fortune of connecting with some folks who do most of the sales work for me. That said, if anybody knows of these $1,000/hr jobs that the article mentions, point me in their direction!
Find out more by following their blog, or jumpstart your career by joining Hired today
-- Remy
Freelance programming: so hot right now. Just ask the 55 million Americans currently engaged in freelance work (more than 1/3 of the workforce), per Freelancers Union’s Freelancing in America 2016 report — up 2 million from 2014. What’s more, this number is expected to go up to 40% by 2020, due in part to the higher pay, higher job satisfaction, increased flexibility, and litany of opportunities contract work provides.
Or, in the words of 27-year-old software engineer James Knight (in an interview with Bloomberg),“I’d rather control my own destiny and take on the risk and forgo the benefits of nap pods and food.” Knight recently ditched his well-paid job writing software for Google to freelance full-time. Turns out, freelance programming pays just as much — if not more — as the most in-demand Google or Facebook jobs. According to Bloomberg, companies are paying as much as $1,000 an hour for talented freelance developers (with the right skill set).
If you’re ready to venture into freelance programming — either as a moonlighter, or potentially full-time freelancer — here’s a handy playbook for where to start finding jobs and building your business:
If you’re a software engineer, you’re likely getting barraged by recruiters and job offers every single day (if not also in the middle of the night). Make a list of all of the recruiters, job matching platforms (like *cough* Hired *cough*), and individuals in your network who have already expressed interested in hiring you. Make sure to reach back out to these inbound contacts, as well as your existing network, to share your availability on a contract basis. One freelance programmer on the Hired platform recommended browsing LinkedIn to see who in your network may be freelancing (and can introduce you to the hiring manager), or leading engineering teams in your preferred industry / stack (and looking for contractors). Your inbox is your own personal freelance leads database; make sure to generate as much demand for your skills as you can.

As a freelancer, the onus is on you to communicate the value you bring to the table, and subsequently, the rates you charge for the value you deliver. Hired freelancer Alex Cone recommends being proactive (and strategic) about marketing yourself — by tweeting, blogging, hosting events, creating a strong portfolio, and generally putting yourself out there. Self promotion is key to freelance success (after all, you’ve got to believe your worth before anyone is going to pay you for it), and can facilitate great relationships. And make sure not to neglect your most important marketing strategy: your portfolio. Pro tip: Read Skillcrush’s comprehensive rundown of what to include in your digital portfolio.
Before ditching your standing desk for the freedom of freelance programming, Wise Bread’s Carrie Smith recommends you stockpile enough cash to comfortably cover 6+ months of living expenses. One way to stash all this cash away while working a full-time job is to take on occasional ‘moonlight’ projects — aka projects you can tackle in the 5pm-9am hours (when your bandwidth/schedule allows). Keep in mind that, in addition to your usual expenses like rent, phone, etc., freelancing comes with additional financial considerations like taxes, health insurance, and retirement savings.

Freelance programmers are at uniquely high risk of burning out, due in part to the endless flexibility afforded by contract work (to set your own schedule, decide your own capacity for contract work, etc), and also because there’s no manager to help you prioritize or helpful colleague to step in when you need a day off. You and you alone are responsible for developing a self care regime that protects your brain from burnout and your sanity from rapidly disintegrating. How does one do that, exactly? One best practice is to be conservative about the number of hours you allocate to each project, making sure to factor ideation and strategic thinking time into your rates. TL;DR: Give yourself more time than you think you need. Additionally, watch out for scope creep from the client — if/when you get emails adding deliverables to your contract, be clear with the requesting individual about how much time/budget this will add to the project and extend the timeline.

Paradoxically, freelancing is a solo endeavor, but one that depends on your ability to socialize. Professionally, socializing (both IRL and URL) — by way of networking at industry events, or online in Slack groups or subreddits — helps you meet new potential clients, befriend fellow freelancers, and stay up-to-date on industry trends. On a personal level, socializing is essential to staving off the loneliness that comes with working independently and without coworkers to brainstorm or banter with everyday. Make sure to explore Facebook groups in search of communities in your niche, sign up for relevant localMeetups, hunt down all of the great many freelance Slack groups(included Hired’s invite-only Slack group for freelancers, and participate in AMAs on Quora and Reddit. For more, join Hired
http://thedailywtf.com/articles/how-to-start-freelance-programming
|
Метки: Sponsor Post |
Where in the World Is Our Website? |
It was a particularly irritating Monday morning, when Travis got a frantic text from his boss. The sun was shining, the birds were nattering, and everyone was greeting him with a smile; it was like everyone in the world had their coffee, but Travis overslept and was going to have to satisfy himself with whatever sludge he could scrape out of the office coffee maker. He had just crossed the threshold when the text arrived:
WEBSITE GONE. WHERE R U?
Travis hurried to his bosss office by way of the coffee pot, and asked, The website is down? Since when?
Its not down! Judging from the red face, and sweating, his bosss blood-pressure was somewhere between deadly and catastrophic explosive failure. Its gone. Deleted. We think it was a security breach.
Travis bit back the I told you so, he desperately wanted to say. The site in question started life as an intranet site, used by insurance agents, built with all the security consciousness that went into intranet sites circa 2004- that is to say, none. A few years later, one of the executives got themselves an iPhone, and asked the next question: Why cant I use this on my phone? Changes were made, security was bolted on, and the entire development team just waited for the other shoe to drop.
They kept it alive, a twisted Frankensteins monster, as new technologies joined the stack, old code lived cheek-to-jowl with new code. Creaky ASP code touched the same database as shiny new NodeJS. What few tests there were had been written in the past year or so, and only touched the newest features.
Eventually, just having it on the iOS web-browser wasnt enough. The agents needed to upload GIS data from their mobile device, and the iPhone sandbox wasnt particularly happy about that. They needed a native app for the device. So Traviss predecessor read a few Obj-C tutorials and whipped up an iOS app that could hold and upload geographical shape files, and present their web application.
With all the moving parts, with the complete lack of baked-in security, a breach had been a long time coming. Travis and his peers had raised their concerns, but an attitude of it hasnt been breached, it must be safe! prevailed. Now they were going to pay for it.
Ive got Neda and Ted going through the logs, his boss said. Brooks is doing recovery. Work with Neda and Ted to see if you can figure out how they got in.
Ted and Neda were the nearest warm bodies when the incident had been reported, and thus got stuck grepping through logs to find the culprit. They had come up with nothing. Theres no sign of any intrusion, Neda said. Nothing unusual in the logs. Which logs we have, I guess- the server holding the web site was wiped.
Travis left them to it, and decided to start at the beginning. He tracked down the agent who first reported the outage, Regina. Regina was based on the East Coast, and thus a few hours ahead of Traviss West Coast office.
My customer gave me a shapefile with some demographic data attached, Regina said. I uploaded, or tried, I guess, but I got an error: invalid file type. The app crashed, and I havent been able to log back in since.
The shapefile was an obvious culprit. Was it compromised in some way? He had her send it to him.
There are dozens of different standard file formats for holding geographical data. There are open standards, like GML, semi-open (but widely used) standards, like Esris shapefile, and proprietary formats like MapInfos TAB file.
Traviss application only supported Esri shapefiles. This was a TABfile. That, at least, explained the error the user saw. But how did that lead to deleting the entire site?
Travis started tracing through the upload process. Shapefiles (and TABfiles) actually contain many subfiles So, multiple files were actually uploaded, and they needed to be stored in a folder following the naming convention …/username/filename.
With that in mind, the upload process did this:
Most of this process happened in the shiny new NodeJS code, but it still was written according to some conventions that Travis had been trying to stamp out. It was a mess, containing some weird logic for solving its problems.
For example, the thousand-line upload function needed to verify the file extension was correct. So what did it do? It used lastIndexOf and substr to split the filename into two parts- filename and extension. If it was correct, it put them back together by doing filename += extension. If it was incorrect- because someone had, for example, uploaded a TABfile instead of a shapefile- the code would send back an HTTP error code using response.end()… but didnt break out of the function.
No return. No thrown exception. If someone uploaded an invalid file, they got an error message, but the file still got uploaded. Worse, since it only put the extension back on filename if the file was valid, the filename was incorrect for the rest of the processing. So, mycustomerdata.tab simply became mycustomerdata.
At this point, the bug was pretty clear in Traviss head. He flipped to the section of code that was responsible for deleting the destination folder.
uploadedFullPathWithUsername = user.name + "/" + filename;
folderPath = path.normalize(uploadedFileFullPathWithUsername.substr(0,
uploadedFullFilePathWithUsername.lastIndexOf(".")) + "/");
fs.removeSync(folderPath);
Since the preceding bug had forgotten the filename extension, uploadedPathWithUsername would have contained something like regina015/mycustomerdata. The lastIndexOf(".") wouldnt find the target data- itd be -1. The JavaScript substr function happily assumes you wanted a 0-length string, and thus returns an empty string. Which means, by the time fs.removeSync is called, the folderPath is a simple /.
In other words, this perfect storm of bad choices had reinvented the venerable sudo rm -rf $1/$2 trap.
Travis presented his findings to his boss. They hadnt been hacked, but this vulnerability could have been exploited by a malicious user. We dodged a bullet, he said, but not to mix metaphors, who knows what other land-mines are in this code?
But youre saying we havent been breached, right?
Well not technically-
Then it must be safe! Fix this bug and get back to your regular work.
[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.
http://thedailywtf.com/articles/where-in-the-world-is-our-website
|
Метки: Feature Articles |