CodeSOD: Tryception |
"If at first you don't succeed, try, try again."
We have all encountered situations where we need to attempt an operation, with full knowledge that the operation might very well fail. And if it does, we should retry it. Usually after a delay, usually with a maximum number of retries.
Today's anonymous submitter inherited a site-scraping application. Already, we're in dangerous territory- site-scraping is inherently fragile, dangerous code. It's more dangerous, of course, when it's written by the culprit behind this:
public void ScrapeASite()
{
try
{
//Some setup work
var doc = HtmlWeb().Load(url); //a synchronous call
//use the returned data to do stuff
}
catch(Exception e)
{
//recurse, and hope the next request for the same domain
//gets a different host from the load balancer
try
{
Console.WriteLine(DateTime.Now + " " + BAD SERVER!!! " + e.Message);
}
catch(Exception)
{ }
//Rinse Repeat
ScrapeASite();
}
}
The Load method getting called is synchronous, which certainly makes this code simpler, even if it's probably not the best idea. If what goes wrong is a timeout, you might be waiting quite awhile as your program hangs.
And when something does go wrong, we handle the exception.
I'm first delighted to see that Console.WriteLine is wrapped in a try/catch. We can't be too careful, I suppose. We'll just swallow that exception, if it happens, and then we call ScrapeASite. Recursively.
This is C#. The .NET runtime does support tail call optimizations, but the compiled Intermediate Language needs to contain certain op-codes to enable it. The F# complier emits those op-codes. The C# compiler does not.
So if the site goes down, or the network is out, or what have you, we start sending request after request by piling frame after frame up on the call stack. The good news is that this method probably only uses a relatively small amount of space on the call stack, which means you can do this many many times before getting a StackOverflowException.
Perhaps the person responsible for this code should try, try, try a little harder to catch their own mistakes.
|
Метки: CodeSOD |
CodeSOD: A Profitable Education |
Today’s anonymous submitter is an experienced Python developer. Their team is significantly less experienced. In the interests of training, someone suggested, “Perhaps we should buy books for everyone.” Our submitter was handed a stack of possible books, and asked to pick the best one to help the team mature.
One book spent some time discussing types, and the conversion between them. By way of example, it provided a handy method which would turn a string into a floating point number:
def str_int(s):
val = "%.2f" % profit
return float(val)
According to the book, this method turns a string into a float, which is why it’s called str_int.
"%.2f" % profit is one of several Python string formatting conventions, and it will take the contents of the variable profit and substitute them where the % appears in the string. In this case, it will be formatted as a floating point with two decimal places. Oh, but wait a moment, the .2f format token requires whatever is being substituted in actually be a floating point value, so the contents of profit couldn’t possibly be a string, or this would fail.
Which, of course, brings us to the largest problem with this code. profit is not the parameter passed in. The parameter passed in is s. s is not used in the method. profit is not declared anywhere in this scope, and according to our submitter, wasn’t declared in any scope.
What this method actually does is crash. What it means to do is take the contents of a floating point variable, truncate it to two decimal places, and then returns it as a float, after taking a round-trip through a string. Which is not the best way to do this in the first place, and it certainly isn’t even the simplest.
I suspect the variable names betray the author’s actual goal for the book: not education, no the respect of their peers, but simply put: profit. The errors in this volume mean that they can work up a second edition, which both corrects these and adds entirely new errors, to promote the third edition!
|
Метки: CodeSOD |
Representative Line: An Equal Crunch |
Rina works in an environment which tends to favor crunch. It's a bit of a feast or famine situation, where they'll coast for months on a pretty standard 9-5 schedule, and then bam, suddenly it's 18 hours days.
No one particularly likes those periods, and code quality takes a nosedive. Co-worker Rusty, though, starts making utterly bizarre decisions when stressed, which is how Rina found this line while doing a code review:
int count = stackRepository.getQueryCount(queryPredicate);
if(count > 0 && count < 2) {
stackEngine.process();
}
"Um... what exactly are you doing with this?" Rina asked.
"Oh, yeah, well, we shouldn't call the process method unless the count is exactly equal to one," Rusty replied.
"Equal to one," Rina repeated, slowly.
Rusty facepalmed. "Crap. You're not gonna tell anyone about this, are you?"
"Your secret's safe with me," Rina said.
That line got caught before going too much further, but when things get really crunched, code reviews start to go out the window. Who knows what other strange choices lurk in that codebase?
|
Метки: Representative Line |
CodeSOD: To Round a Corner |
Last week we saw an attempt to reinvent the ceil function. Tina raised a protest: "6 lines to re-implement a ceil function? We can do better."
//Rounds to 1000d Superior
public int round1000dSup(int value_To_Round) {
int finalResult = 0;
int resultIntermediate = value_To_Round / 1000;
resultIntermediate += 1;
int valueRounded = resultIntermediate * 1000;
if ((valueRounded - value_To_Round) == 1000) {
finalResult = value_To_Round;
} else {
finalResult = valueRounded;
}
return finalResult;
}
This isn't a deeply terrible stab at solving the problem. It's bad, certainly, but it's not an eye-gouging horror. It rounds up to the nearest thousand. It takes an odd-way round to get there, but it works.
This method sits in the middle of a 6000+ line class called Utilities. It sits next to methods like this one, also for rounding:
//Rounds to 100d closest
public int round100tClose(int value_To_Round) {
int finalResult = 0;
int resultInteger = value_To_Round / 100;
System.out.println("Result integer: " + resultInteger);
int remainderDivision = value_To_Round % 100;
System.out.println("Remainder of division in integer: " + remainderDivision);
if (remainderDivision < 50) {
finalResult = resultInteger * 100;
System.out.println("Final resul in range < 50: " + finalResult);
} else {
int valueRounded = (resultInteger * 100) + 100;
System.out.println("Final resul in range > 50");
if ((valueRounded - value_To_Round) == 100) {
finalResult = value_To_Round;
System.out.println("Final resul on Value already Round: " + finalResult);
} else {
finalResult = valueRounded;
System.out.println("Final resul on value not round: " + finalResult);
}
}
return finalResult;
}
Now, we can see that the comments follow a... convention, of sorts. I like the addition of a bazillion printlns, which explains a lot about this code, perhaps more than you think.
Tina inherited this project, and the project's inception was a manager going, "Hey, why should we pay an expensive senior developer to ride herd on a pile of juniors? They all went to college. Let's just have a team of all juniors doing development."
This code is clearly someone's repurposed homework. Sometime during their freshman year, they needed to round numbers, and hacked away until they had this. They handed it in, and probably got a "B", were happy with the grade and moved onto the next assignment.
There we have it: a giant do-anything class, written by people who are still learning the job, without sufficient supervision, released into the wild, until it lands on Tina's desk, where she now gets to try and clean out the overgrowth and turn it into something maintainable.
"At least," she adds, "it's not copy-pasted anywhere else... or is it?"
|
Метки: CodeSOD |
Error'd: The Reason is NULL |
"Turns out that you shouldn’t use your edge browser to download Chrome because of potentially malicious links and...null," wrote Allen B.
Timothy W. writes, "On the surface, it seems that whomever sent this phishing email seemed to know I work in the wardrobe department of a major movie studio. I realized too late that it was just a typo."
"That big old green check is ...misleading, or was this a successful error? I'm in emotional limbo," wrote Lucy W.
David S. writes, "The genius of this is that it protects your accounts in two different ways. Not only does it block your cards from being skimmed(without needing batteries!), at its sale price of lb495 it ensures that your bank account won't have any money in it to get stolen!"
"I don't remember signing up for the Classmates website in 1970, I didn't even get a computer until 1989, but if they say I did, sure I guess so!" Raymond L. wrote.
Andrea writes, "It's pretty cool that a certain well-known email app has started offering 'quick replies', but I'm not feeling it's fully baked yet."
|
Метки: Error'd |
CodeSOD: A Swift Update |
Banks are uniquely identified via a “SWIFT Code”. It’s an ISO Standard. Having an accurate SWIFT code for a given bank is of vital importance to anyone doing financial transactions. With mergers, moves, new branches, and so on, the SWIFT codes you do business with won’t change often, but they will change.
Thus, Philip wasn’t terribly surprised when he got a request to update a pile of SWIFT codes. He couldn’t make the change via the database, though, as no one had permission to do that. He couldn’t edit it through an application UI, because no one had ever built one.
Instead, he had to check out a Java web service from SVN, modify the hard-coded values in the code, deploy the service to production (an entirely manual process), and then invoke the web service via cURL.
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("/writeAccountTableOther/{namespace}")
public Response writeAccountTableOther(@PathParam("namespace") String namespace) {
NamespaceManager.set(namespace);
List accounts = Arrays.asList( new String[] {
"999,Initech Financial Svcs ,ABC123 ",
"998,Initech Investment ,BBC123 " ,
"997,Initech BIC ,CBC123 " ,
"996,Initrode Bank ,DBC123 " ,
"995,Initrode Comercial ,ABC223 " ,
"994,Initrode Industrial Bank ,FFF123 ",
"993,Initrode Millenium Bank ,GAB123 ",
"992,Initech Holdings ,QBC512 ",
"991,Initech Spirit Bank ,IIL512 "
});
for (String account : accounts) {
String[] split = account.split(",");
int i=0;
Entity entity = new Entity("bni_other_acc", split[i].trim());
entity.setProperty("NIBBank", split[i++].trim());
entity.setProperty("Name", split[i++].trim());
entity.setProperty("SwiftCode", split[i++].trim());
DatastoreServiceFactory.getDatastoreService().put(entity);
}
return Response.status(Response.Status.OK).entity("DONE").build();
}
This was the only mechanism for modifying these data values.
|
Метки: CodeSOD |
CodeSOD: Hitting Your Skill Ceiling |
Clia was handed a pile of legacy code and told to upgrade it, but with a very important rule attached: the functionality couldn't change. Any change could break someone's workflow, and thus in the upgraded system, even the bugs had to be reproduced.
Unlike most "legacy" code, this wasn't all that old- it was written in C#. Then again, C# is old enough to drive, so maybe it is old. Regardless, C# has utility methods, like, say, a ceil function. At no point in C#'s history has it lacked this basic functionality.
That, of course, doesn't stop people from reimplementing it badly.
nToken = (nArea / 12).ToString(12).Tokenize("", ",", sToken);
nValue = sToken[0].ToNumber();
nDezimals = ("0," + sToken[1]).ToNumber();
if (nDezimals > 0.0001m){
nValue = nValue + 1;
}
Note, this isn't a function. This representative snippet is the pattern that was copy/pasted, with modification, anywhere someone needed the ceiling of a value. Clia dutifully replicated its behavior, unchanged.
[Advertisement]
Forget logs. Next time you're struggling to replicate error, crash and performance issues in your apps - Think Raygun! Installs in minutes. Learn more.
|
Метки: CodeSOD |
Enterprising Messages |
Percy's employer is an "enterprise vendor". They have a variety of products all within the "enterprise" space. Like most enterprise products, they're sold on the strength of the marketing team's ability to claim with a straight face that they're secure, robust, reliable, and performant.
While the company offered a "cloud" solution for their enterprise suite, the real money was in the on premises version. With on-prem, any updates or upgrades were almost guaranteed to break the entire environment unless the customer shoveled huge piles of cash at the company to get a specialist to come out and do the upgrades.
That was good for the company, but wasn't so great for the specialists. Simple patches could take weeks to perform, not because of any trickiness or difficulty, but because each upgrade step could take days to run.
Percy found out about this when sitting in on a project review meeting.
"For our instant messaging engine," one of his peers, Elizabeth, explained, "just handling the room policy records can take upwards of ten hours at some sites. That's one SQL statement. God forbid the transaction fails for some reason."
"How could it be that bad? How many records is it?" Percy asked.
"Only about 100,000. The problem is the way the data is structured." Elizabeth pulled up the schema.
As an enterprise product, the messaging system prizes configurability and customizability over utility, performance, and common sense. It's not designed to solve a problem, but instead to allow customers to solve problems they didn't know they even had, mostly by inventing them. As a messaging/chat system, they had a concept of "rooms", and the "rooms" could have every aspect about them customized. From how usernames display in the chat, to whether files can be sent, to even whether or not copy-paste is permitted. Of course, the same interface which configured those cosmetic flags also configured role-based permissions, transport layer settings, and whether the messages were compressed before sending to the server.
And with each version of the product, the specific set of fields could change.
Those of you who work in RDBMSes are likely imagining a vast field of relations bound together by foreign keys and indexed to optimize likely query paths. Those of you who are more on the NoSQL side of things are likely imagining a sparse JSON/BSON document, possibly a heavily denormalized representation of the dataset.
Those of you who know enterprise products, or who have read this site before, know what it actually was: gigantic XML documents stored as CLOBs in the database. To add insult to injury, they used SQL Server on the backend, which has had a native XML type with optimized query operations since the mid-2000s.
Percy pulled up the schema on his own machine to explore it. At the center of the schema was a ChatRoomPolicy table. This table had three fields- a PolicyId and the RoomPolicy, which was the main gigantic XML document. In addition to that XML pile, you also had a Visibility column, which contained an XML document which contained ChatRoomVisibility elements- essentially little things, like whether attempting to send a message included a "Cancel" button, or if users could see a "Mute" button to silence the notifications.
Then, of course, you had the ChatRoom table, which had a foreign key reference to the policy which controlled the chat room.
"So, yeah, when we do an upgrade which alters the schema of the RoomPolicy documents," Elizabeth explained, "we have to read every row, parse the XML in our upgrade script, generate the new XML, and then store it. That's if the XML changes- sometimes an upgrade only renames one key, and not every document contains that key."
Percy had seen some pretty horrible things in his section of the product, but nothing quite like this. "Well, at least you can just map the XML document to a class, and mostly automate the changes, right?"
Elizabeth laughed at him. "If we did that, then our customers couldn't make up their own XML keys, and then add their own procedures in our proprietary scripting language which reads them, and then I wouldn't constantly get tickets because some PM at a three-branch bank in East Pilsbury decided they wanted a new field in their chatroom and it happens to collide with one of the fields we already use."
More specifically, the XML didn't have an associated schema. The upgrade script had to be able to handle any arbitrary XML document, identify the parts that the script cared about, if they existed, modify them, if necessary, hopefully without breaking anything the customer had customized, and then actually do the update.
The resulting upgrades could, on a good day, get about 3 records processed every second. With some organizations, the pile of policies applied to chat rooms could extend into the hundreds of thousands (as "private chats" also counted as chat rooms and had policy documents attached). Thus, ten hours just to upgrade a single module of a single service in their enterprise software portfolio. And that's just the upgrade task.
"Wow, I can't imagine how long testing must take," Percy said.
Elizabeth laughed, again. "That's up to the client to schedule. They usually don't."
|
Метки: Feature Articles |
Success Despite Management |
In our industry, we all know that managers cause problems when they try to, well, manage. This invariably causes us to get frustrated. Sometimes when we rebel and try to force them to do the right thing, we are the ones that pay for it with our jobs. Sometimes, they get impatient at our mortal lack of $Deity-level skills to make the magic happen fast enough for them, and we pay for that with our jobs as well.
Occasionally, even though it seems as though managers never pay for their mistakes, Codethulu smiles upon us and gives us a glimpse of a Utopian world...
Back in the mid 1990s, Dennis worked for privately-held Web Accessible Network Kernal, Inc. (WANKCO), a small manufacturer of large automated network test equipment. WANKCO had a couple dozen employees and had not yet developed any big-company policies. Specifically, they did not have the one where you have to use your vacation time or else lose most of it at the end of the fiscal year.
Dennis was very busy as the lead engineer for a very important and very late product that was forecast to make bundles of money for WANKCO. He had been working evenings and weekends designing hardware and firmware and hadn't had a vacation for well over a year. He had lots of vacation time accrued and planned to take a nice long trip after the product was released and seen through its inevitable birthing pains.
One day, WANKCO was purchased by publicly-held Initech. WANKCO quickly inherited a small herd of PHBs, and the alpha PHB informed the minions that, among other PHB things: 1) Vacation carryovers at the end of the fiscal year would be capped according to Initech policy, and 2) Dennis's project was a Critical Corporate Priority and must be finished at the earliest possible date or dire consequences would result for the non-pointy-haired among them. Development staff were to be put on a mandatory fifty-hour work week until the project was complete. A sign-in sheet was provided so they could log their arrival and quitting times each day. Several of the developers happily complied by cutting their work week down to the mandated fifty hours. Apparently, pointiness keeps some people from picking up on the obvious.
The end of the fiscal year was already near when these announcements were made, and the Critical Corporate Priority was within mere weeks of completion. Dennis asked the PHBs for a one-time exception to the vacation carryover policy so that he could see the project across the finish line without sacrificing most of his accrued vacation time. They refused. Thus, with PHB-blessings, Dennis took off on a five-week vacation. With nobody else being qualified to take over his part of the work, the Critical Corporate Priority was delayed by another five weeks. The PHBs couldn't understand why the mandated fifty-hour work weeks did not advance the completion date by a single minute, although Dennis was sure that it made the PHBs appear more pointy than usual.
In spite of finger pointing, insinuating emails and general PHB-isms, Initech and its WANKCO subsidiary survived the delay and the product was eventually shipped.
A parade of PHBs regularly cycled through WANKCO on rotation. After ten years and several changes of ownership, WANKCO went private again. In the process the PHBs were jettisoned, illustrating that not all tales of managerial WTF have an unhappy ending.
Sometimes you just have to wait 'em out.
|
Метки: Feature Articles |
Error'd: Investigation of Satisfaction |
"There are premium translation services, and then, well, there are the rest," Dave P. writes.
"More like Mumbo-Jumbo Mail if you ask me," writes Alicia
Stefan H. wrote, "Green checkmark. Successful completion message. Just...don't look any closer."
Paul S. writes, "So apparently London is now part of the United States. Must be part of the Brexit deal, right?"
"Well, I guess that I'll be going with a different GUI framework," wrote Lucas L.
David B. writes, "PROTIP: When copying items to the desktop, make sure that you have at least 1."
https://thedailywtf.com/articles/investigation-of-satisfaction
|
Метки: Error'd |
CodeSOD: For a Long While |
Here’s a philosophical question. Let’s say you’re searching an array. Is it clearer to use a for loop and break when you find the element, or is it better to use a while loop and break if you hit the end of the array?
Most of us would likely use the for loop, but it wouldn’t be wrong to use the while- maybe just unexpected.
But what if you had forgotten that while loops even exist? An anonymous submitter found this, and distilled its essence for us:
for (int i = 0; i < int.MaxValue, i++)
{
// body of the loop, does not depend on i
if ( /* some condition, does not depend on i */)
break;
}
At first glance, this seems almost like one of those “search the array” loops, where you break upon finding the element. But that’s not what this is. This iterates up to int.MaxValue times, and no internal iteration ever cares about what i holds.
This is almost a while loop. It won’t run forever, but it’ll run for a real long time before giving up. Our submitter noticed because of a large pile of “unused variable” warnings- pretty much every place where you should use a while loop, this developer used the for/break construct.
The upshot, I suppose, is that at least it wasn’t a for-case.
|
Метки: CodeSOD |
Paper (Size), Please |
Terje worked for an IT firm that serviced the purchasing department of a global corporation. To manage purchases, the department used an enterprise shipping and warehousing system that shall be called BLA to protect the guilty. The system ran on a Citrix farm in Norway with all the most impressive resources at its command.
Just after a major upgrade of BLA, sporadic performance issues began cropping up in the Brazil and Perth offices. When users tried to generate new reports, BLA would hang for several minutes. In Norway, Terje and his colleagues couldn't reproduce the problem. They went through every reasonable troubleshooting step, but failed to isolate the root cause of the issue. The vendor of BLA, also based in Norway, couldn't duplicate the issue, either. Months passed with no resolution in sight.
Lest one should think that everything was sunshine and roses in Norway, the users there ran into their share of quirky issues as well. A common one was the "Printer not found" error message when a user tried to generate a report. Usually, this happened whenever a user removed or inserted their laptop into a docking station while logged into BLA. Simply rebooting Windows while the laptop was docked fixed the issue. The vendor explained that BLA had to have a default printer set within the local Windows environment so it could find out how big a piece of A4 paper was. This would ensure that BLA would always use the correct paper size for reports. This behavior seemed odd to Terje, but he kept it in mind.
One day, when he was fielding yet another performance issue from Brazil, the above tidbit occurred to Terje and bestowed a spark of inspiration.
"Try this for me," he told the user on the phone, sitting up straighter in his chair. "Log out of Citrix, then set your default printer to a PDF creator."
"What?" the user asked. "What does that have to do with anything?"
"I know it sounds weird, but can you just give it a try?" Terje pleaded. "If it doesn't help, you can change the setting right back."
"OK ..." the user replied, skeptical.
Sure enough, once the user made the change and logged back in to Citrix, he was able to generate a report almost instantly.
"How did that work?!" he asked.
"You're connecting to our Citrix server in Norway, opening BLA, and attempting to generate a report," Terje replied. "When you do that, BLA goes, 'How big is size A4 paper? I'd better ask the default printer.' In your case, the default printer was pointing to a device in your office in Brazil. So BLA was connecting from Norway to that printer halfway around the world, and was waiting for it to tell it how big A4 is. That's why everything was so slow!" Terje slapped a hand against his desk in triumph.
"How odd!" the user said. "I'm glad it works now, though!"
Terje was even happier to have cracked that enduring mystery. He got to work assembling a knowledge base document and compiling the evidence needed to file a change request with BLA's vendor.
|
Метки: Feature Articles |
It's a Little Stale |
Megan K’s organization does the sane and reasonable thing: they cache all of their dependencies locally, and their CI/CD process pulls from the local cache. Since they’re in the Python world, this means pulling from PyPI using Bandersnatch.
Someone set up the Bandersnatch job. Someone linked it into their CI/CD process. No one wanted to claim credit when it started failing. Every five minutes, Bandersnatch tried to contact PyPI. Every five minutes, it got a StalePage error, specifically complaining about a “stale serial”, and sent an alert email to the entire dev team. Every five minutes, the entire dev team ignored the error. For ten days.
The office turned into a tense standoff. No one wanted to talk about the errors, since the first one to bring it up was going to be the one who had to fix it. Each day could be underscored by Ennio Morricone.
Megan caved first. Instead of using rules to filter her inbox, she manually deleted each message. Eventually, sick of getting spammed, she did some research, and shared her findings with the developers.
Megan started where anyone would start debugging HTTP requests: with curl. The curled the failing URL, first from her machine, and when that worked, from the Bandersnatch machine. That also worked. Even as a Python script, running on the same machine, sending a very similar request, failed.
Megan fired up a Python REPL and imported the requests library, which is used for sending HTTP requests. She sent a request, and that failed. curl always got a fresh serial, requests always got a stale serial. Obviously, there was something different about the requests.
Megan checked the headers, and found two key differences: the User-Agent and the Accept-Encoding headers. Thinking the obvious, she tried setting curl to use the same User-Agent as requests- and it kept working. Changing the User-Agent in requests didn’t fix the problem.
But changing the Accept-Encoding did. If Megan sent a request with Accept-Encoding: gzip, deflate, the PyPI loadbalancer routed her to a stale cache server, every time. Accept-Encoding: '', on the other hand, always got a fresh server. By default, requests used gzip, deflate. Bandersnatch, in turn, used the default settings for requests.
That of course, wasn’t enough. Eventually, the cache server that Bandersnatch was getting routed to would also become stale, so Megan had to add an arbitrary (and highly variable) parameter to her requests- specifically, a URL parameter called cache-bust which was always set to the current timestamp.
An issue was raised with PyPI, which is still open at the time of this writing. Obviously, it’s some simple misconfiguration in the load balancing and caching, or perhaps an intentional configuration based on bad assumptions, but the moral of the story: Megan was glad they were caching all of their dependencies locally, just in case PyPI ever went really wrong.
|
Метки: Feature Articles |
CodeSOD: A Tern at the Build Process |
Justin Self inherited an internal build tool. Rome may not have been built in a day, but this tool was. It “simplifies” provisioning development environments, claiming machines in the environment for certain tasks, and so on.
(e.BuildStatus == null ?
(e.Branch == null ? "" : ($"\nBranch: <{e.BranchUrl}|{e.Branch}>")) :
($"\n{(e.BuildStatus == "Building" ? "Building" : e.BuildStatus == "Success" ?
$"Built" : "Build failed")}: <{(e.BuildStatus == "Success" ?
e.BuildReleaseUrl : e.BuildUrl)}|{e.BuildRelease}>") +
$"{GetCardUrl(e.Branch)}") +
$"\n{(e.DeployStatus == "Deploying" ?
"Deploying" : e.DeployStatus == "Success" ?
"Deployed" : "Deploy failed")}:
<{e.DeployUrl}|{e.DeployRelease}>{GetCardUrl(e.DeployRelease)}"
Unfortunately, this ternary is one of twenty in a row. Justin writes:
I wanted to make a change to it but… after the 4th ternary, I could no longer remember what I was doing and had trouble picturing my children’s faces.
https://thedailywtf.com/articles/a-tern-at-the-build-process
|
Метки: CodeSOD |
Error'd: We Need a Windows Install CD in Aisle 7 |
"Encountered this one while attempting to weigh some vegetables and well...the scale crashed?" writes Sam.
Johnwrote, "Should I start binge drinking to fix this number?"
"Someone puked a UI all over my screen. The best part, although the video is buffering where it should be playing, the video behind the text is playing like this is normal." Steven B writes.
"Wow, Amazon is really angry about my promo code...which is particularly remarkable given that I hadn't entered one," wrote Kai J.
Ian W. wrote, "So, in Cyberpower's TOS, wouldn't 'Users of the Site must not monitor any content on this Website by using any manual process of any kind.' also include me (or anybody else) manually viewing it in a web browser?"
"Wouldn't 'less old' actually be 'new'?" wrote Michael P.
https://thedailywtf.com/articles/we-need-a-windows-install-cd-in-aisle-7
|
Метки: Error'd |
Representative Line: Created Equal |
Let's say you have an enum. You have an array of objects, where one of the fields is of that enum type. You want to filter the array of objects where the value of the enum is PAYMENTMETHOD.
You also hate equals signs.
Jacqueline found IntelliJ screaming out a litany of warnings, and while tracking down the reasons, she found this bit of Java:
.filter(e -> Arrays.asList(SRN.Type.PAYMENTMETHOD).contains(e.getTxfr().getSourceOrThrow().getType()))
Arrays.asList has an array-valued parameter, so it turns SRN.Type.PAYMENTMETHOD into a List object with one item in it, then checks to se if e.getTxfr()...getType()'s result happens to be in that list. With one object.
The list being filtered might contain many objects- this is part of a pretty large transaction processing system which is handling millions of records. And yes, this code creates a new list object with one item in it for every record.
Jacqueline was able to significantly increase throughput by taking the radical action of replacing this with a more straightforward equals comparison.
|
Метки: Representative Line |
The Hardcode to Success |
Rodrigo was but a simple software development intern eager to prove himself. He would always volunteer for the menial tasks that nobody else wanted to do. "Nobody else" mainly consisted of Justin, Rodrigo's supervisor. Justin wasn't a big fan of doing stuff so he was glad to have an intern that was ready and willing.
Justin got a request from the network administrators to create a system status application to interface with their servers. They wanted to receive alert emails every hour on the hour if anything on the servers had a conniption. If everything was ok, maintain radio silence. To do this, a simple app would need to be created to pass system health check results to Pushbullet, which would take care of sending the alerts. Rodrigo didn't even wait for Justin to finish. "I'll do it!"
Rodrigo was excited to get his development environment set up with an instance of Pushbullet so he could start slinging emails. He spent the week coding and extensively testing his app and by Friday, his phone buzzed with an alert. Something about having his code send something out to his phone seemed super cool and futuristic.
Rodrigo wasn't exactly sure how to simulate a system failure so his phone only got emails saying everything was hunky-dory. All he had left to do was to add a condition to not actually send the hunky-dory alerts since the network admins didn't want their phones going off every hour.
Ready to proudly show off his handiwork, Rodrigo called Justin over for a demo. The demo consisted of Justin half paying attention, half texting on his phone, and saying "Yeah, ok" every couple minutes. When Rodrigo was done, Justin nonchalantly said, "Go ahead and throw it out on the production server whenever". Rodrigo wasn't expecting that but he was glad to finally have an app of his go to production.
He threw the code out on the production server, fired it up, sent an email letting the admins know to expect an alert in case of trouble, then checked out for the weekend. He bragged to his friends over several beers about how his code was working all weekend while he got to have fun.
Rodrigo strolled in Monday morning to find a red-faced Justin standing at his desk, arms crossed. "Rodrigo! We had a major system failure over the weekend!"
Confused, Rodrigo played an optimistic card, "So when that happened, my app notified everyone... right?"
"No, it didn't!" Justin shouted, banging his hands down on the desk. "Your app didn't do jack squat to alert anyone, now we've lost nearly 30 hours of production data! Have a seat and think about how we're going to fix this while I review your code."
Justin opened Rodrigo's source code at his computer and began scrolling through it. It didn't take long for him to find the offending line -
"Access-Token: " + accessToken + "\r\n" +
"Content-length: 99\r\n"
"Content-Type: application/json\r\n" +
"Connection: close\r\n\r\n" +
Justin called Rodrigo over to shove his nose in the code mess he made. "Why on earth did you hardcode the length??"
Rodrigo meekly replied, "I didn't want to create a function to count the bytes so I made a Python script to count the amount of characters in the response. I figured since it always returned 99 characters, I could hardcode it to that. Is that bad?"
Justin angrily explained how when the response was anything but a clean health check, it would return an error message. An error message would most definitely be more than 99 characters, but it would get truncated to 99, where the success message condition he added would think everything was great. Thus, no alert would be passed to Pushbullet.
In the aftermath, Rodrigo was relieved of his internship while Justin was left to explain why he allowed an inexperienced intern to push code that hadn't been reviewed to production. In the end, it was hard to say who learned more from the internship experience.
|
Метки: Feature Articles |
CodeSOD: We Tried Nothing |
Initrode bought a UI widget library from Initech. Years passed, and eventually Initech went under. Initrode kept on keeping on, and kept using the library. Management shuffles happened, IT got downsized, and new development got outsourced.
Merlin B worked for the company that got the contract. Somehow, someone got the source code from Initech's GUI library.
public partial class SomeProcessUserControl : SomeSlightlyDifferentProcessUserControl
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
try
{
}
catch (Exception ex)
{
string logGuid = LoggingService.LogError(ex.ToString(), string.Format(""));
}
}
}
"I immediately thought of Linkin' Park's song 'In the End'," Merlin writes. "He tried so hard, and got so far, but in the end, it doesn't even matter."
It's pretty clear to me how this happened: company standards. One OnLoad somewhere threw an exception, and some pointy-haired-boss made a new standard: "All OnLoads must contain a try/catch and log the error out." It's also pretty clear what finally drove Initech under.
|
Метки: CodeSOD |
CodeSOD: Longer Isn't Better |
Andrew H writes “this is an interface for one of our Spring Data repositories”. If you’ve ever looked at Spring’s documentation, you know the punchline. Spring has certain naming conventions that have become a notorious.
Spring Data is an ORM, and among other things, it allows you to design interfaces which are translated into a series of queries based on the naming conventions. So, for example, a method named findDistinctByTenantId would turn into a query in the database. It’s a useful convenience for simple CRUD operations, but for more complex queries, you’re still better off writing your SQL in an @Query annotation. SQL is still the best way to build complicated RDBMS queries.
That doesn’t mean you have to use SQL. Andrew’s co-worker provided this method:
public Page findDistinctByTenantIdAndTitleIgnoreCaseContainingAndFlagsNotNullAndFlagsResolutionTypeValueOrTenantIdAndDescriptionIgnoreCaseContainingAndFlagsNotNullAndFlagsResolutionTypeValueOrTenantIdAndEmailIgnoreCaseContainingAndFlagsNotNullAndFlagsResolutionTypeValueOrTenantIdAndContactNameIgnoreCaseContainingAndFlagsNotNullAndFlagsResolutionTypeValue
(Long tenantId, String title, String resolutionTypeValue, Long tenantId2, String description, String resolutionTypeValue2, Long tenantId3, String email, String resolutionTypeValue3, Long tenantId4, String contactName, String resolutionTypeValue4, Pageable pageable);
As an aside, this convention doesn’t let you reuse a parameter in multiple conditions, so those multiple tenantId, tenantId2, etc. parameters? They all need to get the same value. Ditto on all the resolutionTypeValue parameters. This may not be the longest method name ever, but it’s certainly a strong contender.
|
Метки: CodeSOD |
Error'd: Real Formatting Advice |
"VMware Team decided to send me some useful advice via e-mail," writes Antti T.
"Costco and Dell have teamed up to offer the latest in gaming storage technology...the Hard Frive?" wrote Scott H.
William K. wrote, "Yeah, more like City Faillines."
Sam writes, "They don't look so angry to me...or very bird-like for that matter either."
Mike S. writes, "Yeah, but what if I want to pay in GBP?
"Well, to be fair, they did not list graphing as an area of expertise," wrote Louis G.
[Advertisement]
Forget logs. Next time you're struggling to replicate error, crash and performance issues in your apps - Think Raygun! Installs in minutes. Learn more.
|
Метки: Error'd |