CodeSOD: Classic WTF: Functional Encryption |
It's Thanksgiving Day in the US. Yesterday, we looked at a classic "encryption" story, and today, we should all be thankful that we don't have to support this encryption code. Original --Remy
Richard's company builds, hosts, and maintains a variety of small- and mid-sized web-based applications for their clients. Recently, one of their clients asked Richard to help audit a fraudulent transaction, which meant that Richard needed to dig through the code to see how to decrypt bank account numbers stored in the database. The search led him to H88493247329(), the method responsible for encrypting customer data. After spending a minute to add linebreaks and rename the variables, Richard asked his coworker why he obfuscated the code. His coworker scoffed, you should always encrypt your encryption functions -- it's completely insecure otherwise
function H88493247329($B89424235) { //ED: Linkebreaks added global $a,$e,$m,$H; $X42342234 = $H . "." . $m . "-" . $a; $KJD234 = fopen($X42342234,"r"); $MMNVUD884 = fread($KJD234,filesize($X42342234)); fclose($KJD234); $MQUFI3 = mcrypt_module_open('','','''); $MMNVUD884 = substr($MMNVUD884,0,mcrypt_enc_get_key_size($MQUFI3)); $JF8_size = mcrypt_enc_get_iv_size($MQUFI3); $JF8 = mcrypt_create_iv($JF8_size, MCRYPT_RAND); if (mcrypt_generic_init($MQUFI3,$MMNVUD884,$JF8)!=-1) { $KIDO83R4234FFS = mcrypt_generic($MQUFI3,$B89424235); mcrypt_generic_deinit($MQUFI3); mcrypt_module_close($MQUFI3); } return $KIDO83R4234FFS; }
https://thedailywtf.com/articles/classic-wtf-functional-encryption
Метки: CodeSOD |
CodeSOD: Classic WTF: Top-grade, SHA1 Encryption |
Is it that time of year already? Here in the US, we're prepping for the Thanksgiving holiday, so let's take a trip way back into the archives, and learn about the life of a moderately-paid-consultant. Original --Remy
Paul B always thought of himself as a moderately-paid consultant. With no real overhead, a policy against ties when meeting with prospective clients, and a general pickiness about the projects he'll take on, his rates tend to be pretty low. One company that looked right up his alley was a mid-sized manufacturing company that wanted a custom webshop. They went to the highly-paid consultants in town, but weren't too happy with the six-figure price tag. Paul's quote was in the five-figure range, which he felt was pretty moderate given that it was a several month project. Of course, the company wasn't too happy with his quote either, so they searched high and low for a three- or four-figure price. They eventually found one overseas.
Despite losing the bid, Paul never bothered unsubscribing from the company's mailing list - there was always something exciting about learning the latest in gimbal clamps and engine nozzle extensions. About a year and a half later, he received an exciting newsletter announcing that the webshop was finally live. Out of curiosity, he created an account to check things out. A few days later, he received an apology for lost orders - they didn't know who had ordered what, so they sent it to everyone who had signed up. And then came the "data breach" email — everyone's personal data (which, for Paul, was just his throw-away email) was now in the hands of some hackers. You get what you pay for never rang so true.
The day following the breach, the company contacted him to see if he was still available for consulting. Apparently, their overseas programmers couldn't figure out how anyone was getting in the system, since they had used "Top-grade, SHA1 Encryption." Curiosity won the day, so Paul asked for a copy of the source code. He couldn't find anything related to encryption, so he performed a search for "sha1". This was the only line that came up:
$result = mysql_query( "SELECT * FROM users " . " WHERE SHA1(username) = SHA1('" . $_REQUEST["username"] . "') " . " AND SHA1(password) = SHA1('" . $_REQUEST["password"] . "')");
Paul told the company he couldn't help them out, and suggested they go to the highly-paid consultants. A few days later, the company's newsletter reported that the webshop was closing down for some "upgrades" - a year later, it's still under construction.
https://thedailywtf.com/articles/classic-wtf-top-grade-sha1-encryption
Метки: CodeSOD |
CodeSOD: Production Comments |
A fair bit of "bad code" requires at least a passing understanding of the language in question, or the domain involved. But bad comments transcend programming languages. Vilx sends us this one, which comes from code which is definitely running in production.
// WARNING!!! Special case for [external API] testing.
// DO NOT LET THIS PIECE OF CODE FIND IT'S WAY TO PRODUCTION
Adding more commentary almost feels like gilding the lilly. Almost.
One of the main objections to putting loads of comments in your code is that over time the code changes, and if the comments don't change with them, confusion results. Which, not only is this not a comment you want to see in your production code, it's not an accurate comment. Vilx explains:
In all truth the particular code (or even the codebase) isn't all that bad; and the lines that followed are completely harmless in production…
Метки: CodeSOD |
CodeSOD: Pixel Perfect Design |
Octavia (previously) didn't just inherit a C# application with dodgy approaches to string handling. It's also an application with questionable understandings of CSS.
CSS is far from perfect, and offers a lot of pitfalls and traps. There's a reason the "impossibility" of vertically centering text is a punchline. It's so flexibly declarative that, in many cases, there are many ways to achieve the same styling result, and it's difficult to pick out the correct one. But one would hope that developers could at least avoid the obviously terrible ones.
<div class="positioning"><span><div class="positioning"><span><div class="positioning">
My Page Title
div>span>div>span>div>
This was not generated HTML, at least as it exists in the codebase. Someone checked this in. Whether they scripted it or copy-pasted remains a mystery. What's less mysterious is the purpose.
Octavia doesn't have the "positioning" class to share, but it sets a number of properties. Only one is relevant here: it adjusts the width of the div by one pixel. The gigantic pile of divs and spans above exists to center the text on the page. Horizontally.
There are a lot of wrong ways to do that in CSS, but this is arguably one of the most wrong.
Метки: CodeSOD |
Error'd: Reduced Complexity, Increased Errors |
"I tried a more complex password and got the same error message, but after trying with a shorter password, it let me through!" wrote Sameer K.
Lucas T. writes, "Translation: 'Dear ladies and gentlemen, because of an internet failure (some identifying info here), the electronic signature and the owl are unavailable. The issue is being worked on. Kind regards, your application support.' Well, isn't this just great. How exactly am I supposed to work without the owl!?"
"I was looking into time issues regarding backing up my Mac with TimeMachine and saw that it REALLY MUST BE A TIME MACHINE AFTER ALL!!" Mike S. wrote.
Joel B. writes, "3D printing my desserts? Sign. Me. Up."
"Huh. Apparently someone hacked my Facebook account before I was born," wrote Rob.
https://thedailywtf.com/articles/reduced-complexity-increased-errors
Метки: Error'd |
CodeSOD: Prepend Eternal |
Octavia inherited a decade old pile of C#, and the code quality was pretty much what one would expect from a decade old pile that hadn't seen any real refactoring: nothing but spaghetti. Worse, it also had an "inner platform" problem, as everything they put in their API could conceivably be called by their customers' own "customizations".
One small block caught her eye, as suspicious:
public void SomeFunctionality
{
// Other functionality here
int x = SomeIntMethod();
String y = PrependZeros(x.ToString());
// Do other things with y here
}
That call to PrependZeros
looked… suspicious. For starters, how many zeroes? It clearly was meant to padd to a certain length, but what?
public String PrependZeros(string n)
{
if (n.Length == 1)
{
return "00" + n;
}
else if (n.Length == 2)
{
return "0" + n;
}
else
{
return n;
}
}
We've reimplemented one of the built-in formatting methods, badly, which isn't particularly unusual to see. This method clearly doesn't care if it gets a number that's greater than 3 digits, which maybe that's the correct behavior? Inside the codebase, this would be trivial for Octavia to remove, as its only invoked that one time.
Except she can't do that. Because the original developer placed the code in the namespace accessible to customer customizations. Which means some unknown number of customers might have baked this method into their own code. Octavia can't rename it, can't remove it, and there's no real point in re-implementing it. Maybe someday, they'll ship a new version and release some breaking changes, but for now, PrependZeros
must live on, just in case a customer is using it.
Every change breaks somebody's workflow.
Метки: CodeSOD |
Big Iron |
Skill which you don’t use regularly can get rusty. It might not take too much to get the rust off, and remind yourself of what you’re supposed to be doing, but the process of remembering what you’re supposed to do can get a little… damaging.
Lesli spent a big chunk of her career doing IT for an insurance company. They were a conservative company in a conservative industry, which meant they were still rolling out new mainframes in the early 2000s. “Big iron” was the future for insurance.
Until it wasn’t, of course. Lesli was one of the “x86 kids”, part of the team that started with desktop support and migrated into running important services on commodity hardware.
The “big iron” mainframe folks, led by Erwin, watched the process with bemusement. Erwin had joined the company back when they had installed their first S/370 mainframe, and had a low opinion of the direction the future was taking. Watching the “x86 kids” struggle with managing growing storage needs gave him a sense of vindication, as the mainframe never had that problem.
The early x86 rollouts started in 2003, and just used internal disks. At first, only the mail server had anything as fancy as a SCSI RAID array. But as time wore on, the storage needs got harder to manage, and eventually the “x86 kids” rolled out a SAN.
The company bought a second-hand disk array and an expensive support contract with the vendor. It was stuffed with 160GB disks, RAIDed together into about 3TB of storage- a generous amount for 2004. Gradually every service moved onto the SAN, starting with file servers and moving on to email and even experiments with virtualization.
Erwin just watched, and occasionally commented about how they’d solved that problem “on big iron” a generation ago.
Storage needs grew, and more disks got crammed into the array. More disks meant more chances for failures, and each time a disk died, the vendor needed to send out a support tech to replace it. That wasn’t so bad when it was once a quarter, but when disks needed to be replaced twice a month, the hassle of getting a tech on-site, through the multiple layers of security, and into the server room became a burden.
“Hey,” Lesli’s boss suggested, circa late 2005. “Why don’t we just do it ourselves? They can just courier over the new drives, and we can swap and initialize the disk ourselves.”
Everyone liked that idea. After a quick round of training and confirmation that it was safe, that became the process. The support contract was updated, and this became the process.
Until 2009. The world had changed, and Erwin’s beloved “big iron” was declining in relevance. Many of his peers had retired, but he planned to stick it out for a few more years. As the company retired the last mainframe, they needed to reorganize IT, and that meant all the mainframe operators were now going to be server admins. Erwin was put in charge of the storage array.
The good news was that everyone decided to be cautious. Management didn’t want to set Erwin up for failure. Erwin, who frequently wore both a belt and suspenders, didn’t want to take any risks. The support contract was being renegotiated, so the vendor wanted to make sure they looked good. Everyone was ready to make the transition successful.
The first time a disk failed under Erwin’s stewardship, the vendor sent a technician. While Erwin would do all the steps required, the technician was there to train and supervise.
It started well. “You’ll see a red light on the failed disk,” the technician said.
Erwin pointed at a red light. “Like this?”
“Yes, that exactly. Now you’ll need to replace that with the new one.”
Erwin didn’t move. “And I do that how? Let’s go step-by-step.”
The tech started to explain, but went too fast for Erwin’s tastes. Erwin stopped them, and forced them to slow it down. After each step, Erwin paused to confirm it was correct, and note down what, exactly, he had done.
This turned a normally quick process into a bit of a marathon. The marathon got longer, as the technician hadn’t done this for a few years, and was a bit fuzzy on a few of the steps for this specific array, and had to correct themselves- and Erwin had to update his notes. After what felt like too much time, they closed in on the last few steps.
“Okay,” the tech said, “so you pull up a web browser, go to the admin page. Now, login. Great, hit ‘re-initialize’.”
Erwin followed the steps. “It’s warning me about possible data loss, and wants me to confirm by typing in the word ‘yes’?”
“Yeah, sure, do that,” the tech said.
Erwin did.
The tech thought the work was done, but Erwin had more questions. Since the tech was here, Erwin was going to pick their brain. Which was good, because that meant the tech was still on site when every service failed. From the domain service to SharePoint, from the HR database to the actuarial modeling backend, everything which touched the SAN was dead.
“What happened,” Erwin demanded of the tech.
“I don’t know! Something else must have failed.”
Erwin grabbed the tech, Lesli, and the other admins into a conference room. The tech was certain it couldn’t be related to what they had done, so Erwin escalated to the vendor’s phone support. He bulled through the first tier, pointing out they already had a tech onsite, and got to one of the higher-up support reps.
Erwin pulled out his notes, and in detail, recounted every step he had performed. “Finally, I clicked re-initialize.”
“Oh no!” the support rep said. “You don’t want to do that. You want to initialize the disk, not re-initialize. That re-inits the whole array. That’s why there’s a confirmation step, where you have to type ‘yes’.”
“The on-site tech told me to do exactly that.”
The on-site tech experience what must have been the most uncomfortable silence of their career.
“Oh, well, I’m sorry to hear that,” the support rep said. “That deletes all the header information on the array. The data’s still technically on the disks, but there’s no way to get at it. You’ll need to finish formatting and then recover from backup. And ah… can you take me off speaker and put the on-site tech on the line?”
Erwin handed the phone over to the tech, then rounded up the admins. They were going to have a long day ahead getting the disaster fixed. No one was in the room to hear what the support rep said to the tech. When it was over, the tech scrambled out of the office like the building was on fire, never to be heard from again.
In their defense, however, it had been a few years since they’d done the process themselves. They were a bit rusty.
Speaking of rusty, while Erwin continued to praise his “big iron” as being in every way superior to this newfangled nonsense, he stuck around for a few more years. In that time, he proved that he might never be the fastest admin, but he was the most diligent, cautious, and responsible.
Метки: Feature Articles |
CodeSOD: Mod-El Code |
Long-lived projects can have… interesting little corners. Choices made 13 years ago can stick around, either because they work well enough, or because, well, every change breaks somebody's workflow.
Today's anonymous submitter was poking around the code base of a large, long-lived JavaScript framework. In a file, not modified since 2007, but still included in the product, they found this function.
_getAdjustedDay: function(/*Date*/dateObj){
//FIXME: use mod instead?
//summary: used to adjust date.getDay() values to the new values based on the current first day of the week value
var days = [0,1,2,3,4,5,6];
if(this.weekStartsOn>0){
for(var i=0;i<this.weekStartsOn;i++){
days.unshift(days.pop());
}
}
return days[dateObj.getDay()]; // Number: 0..6 where 0=Sunday
}
Look, this is old JavaScript, it's date handling code, and it's handling an unusual date case, so we already know it's going to be bad. That's not a surprise at all.
The core problem is, given a date, we want to find out the day of the week it falls on, but weeks don't have to start on Sunday, so we may need to do some arithmetic to adjust the dates. That arithmetic, as the FIXME
comment helpfully points out, could easily be done with the %
operator.
Someone knew the right answer here, but didn't get to implementing it. Instead, we have an array of valid values. To calculate the offset, we "roll" the array using a unshift(pop)
combo- take the last element off the array and plop it onto the front. We also have a bonus unnecessary "if" statement- the "for" loop would have handled that.
This isn't the first time I've seen "populate an array with values and roll the array instead of using mod", and it probably won't be the last. But there's also a bonus WTF here. This function is invoked in _initFirstDay
.
_initFirstDay: function(/*Date*/dateObj, /*Boolean*/adj){
//adj: false for first day of month, true for first day of week adjusted by startOfWeek
var d = new Date(dateObj);
if(!adj){d.setDate(1);}
d.setDate(d.getDate()-this._getAdjustedDay(d,this.weekStartsOn));
d.setHours(0,0,0,0);
return d; // Date
}
So, first off, this function does two entirely different things, depending on what you pass in for adj
. As the comment tells us, if adj
is false, we find the first day of the month. If adj
is true, we find the first day of the week relative to startOfWeek
. Unfortunately, I'm not sure that comment is entirely correct, because whether or not adj
is false, we do some arithmetic based on _getAdjustedDay
. So, if you try this for a date in November 2020, with weeks starting on Sunday, you get the results you expect- because November 1st was a Sunday. But if you try it for October, the "first day" is September 27th, not October 1st.
Maybe that's by intent and design. Maybe it isn't. It's hard to tell from the comment. But the real bonus WTF is how they call this._getAdjustedDay
here- passing in two parameters. To a function which only expects one. But that function does use the value passed in anyway, since it's a property of the class.
Even code that we can safely assume is bad just from knowing its origins can still find new ways to surprise us.
Метки: CodeSOD |
Announcements: What the Fun Holiday Activity? |
Time just flies right past, and before you know it, the holidays will be here. Which is why you had better hurry up and try your hand at giving us the best WTF Christmas Story ever, to help us found a new holiday tradition. Or at least, give us one bright spot in the yawning abyss of 2020.
Can you teach us the true meaning of WTFMas?
We want your best holiday story. Any holiday is valid, though given the time of year, we're expecting one of the many solstice-adjacent holidays. This story can be based on real experiences, or it can be entirely fictional, because what we really want is a new holiday tradition.
The best submissions will:
Are you going to write a traditional story? Or maybe a Dr. Seussian rhyme? A long letter to Santa? That's up to you.
Submissions are open from now until December 11th. Use our submission form. Check the "Story" box, and set the subject to WTF Holiday Special
. Make sure to fill out the email address field, so we can contact you if you win!
The best story will be a feature on our site, and also receive some of our new swag: a brand new TDWTF hoodie, a TDWTF mug, and a variety of stickers and other small swag.
The 2 runners up will also get a mug, stickers and other small swag.
Get writing, and let's create a new holiday tradition where opening the present may create more questions than it answers.
https://thedailywtf.com/articles/what-the-fun-holiday-activity-1
Метки: Announcements |
CodeSOD: Unset-tled |
Alleen started by digging into a PHP method which was just annoying. _find_shipment_by_object_id
would, when it couldn't find the ID, return false
, instead of the more expected null
. Not terrible, but annoying. Worse, it didn't return the shipment eihter, just a key which could be used to fetch a shipment from an array.
Again, all that's just annoying.
It was when looking at the delete_shipment
method that Alleen had the facepalm moment.
public function delete_shipment($object_id)
{
$key = $this->_find_shipment_by_object_id($object_id);
if ($key !== FALSE) {
$obj = $this->_shipments[$key];
unset($obj, $this->_shipments[$key]);
}
return $this;
}
The PHP unset
method takes a list of variables, including potentially array elements, and deletes them. For whatever reason, the person who wrote this code decided to fetch the value stored in the array, then delete the variable holding the value and the array index holding the value, when the goal was simply to delete the element from the array.
They just enjoyed deleting so much, that they needed to delete it twice.
Alleen also wonders about the return $this
. It seems like the intent was to build a fluent, chainable API, but the code is never used that way. We're left with a simple mystery, but at least they couldn't return
twice.
Метки: CodeSOD |
Error'd: Hate the Error and Hate the Game |
"Somehow, a busy day for Blizzard's servers is going to last for around 6 months," writes James G.
"So, is interpreting error messages a sport now?" Jay C. wrote.
Drew W. writes, "I'm not sure how, but Sparkpost thinks I've had over 130 emials opened for every one I've sent!"
"I...may have a problem staying off of my phone," Kevin V. writes.
Gordon wrote, "Kind of sums up the 2020 season, doesn't it?"
https://thedailywtf.com/articles/hate-the-error-and-hate-the-game
Метки: Error'd |
CodeSOD: The Default Value |
Cicely (previously) returned to the codebase which was providing annoyances last time.
This time, the code is meant for constructing objects based on a URL pattern. Specifically, the URL might have a format like api/resource/{id}
. Looking at one of the constructors, though, it didn’t want an ID, it wanted an array of them. Cicely wasn’t passing multiple IDs off the URL, and wasn’t clear, from the documentation, how it worked, how you supplied those IDs, or frankly, what they were used for. Digging into the C# code made it clear, but still raised some additional questions.
int[] ids = Request.FormOrQuerystring("ids").EnsureNotNull().Split(",").
Select(item => item.ToInt32()).Concat(new int[] { id }).ToArray();
Whitespace added for readability, the original was on one line.
This is one of those cases where the code isn’t precisely bad, or wrong. At worst, it’s inefficient with all the LINQs and new arrays. It’s just… why would you do this this way?
At its core, we check the request for an ids
property. EnsureNotNull()
guarantees that we’ll see a value, whether there is one or not, we Split
it on commas, project the text into Int32
using Select
… and then concatenate a one element array onto the end, containing our id
off the URL.
Perhaps someone wanted to avoid branching logic (because it’s potentially hard to debug) or maybe wanted some “functional purity” in their programming. Maybe they were just trying to see how much they could cram into a single line of code? Regardless, Cicely considers it a “most imaginative way to set a default value”. It’s certainly clever, I’ll give it that.
Метки: CodeSOD |
CodeSOD: Testing Architectures |
Marlyn’s employer ships software for a wide variety of CPU architectures. And depending on which branch of the product you were digging into, you might have code that builds for just i386, x86_64, PPC, and PPC64, while another branch might add s390, s390x, and aarch64.
As you might imagine, they have a huge automated test suite, meant to ensure that changes don’t break functionality or compatibility. So it’s a pity that their tests were failing.
The error messages implied that there were either missing or too many files, depending on the branch in question, but Marlyn could see that the correct build outputs were there, so nothing should be missing. It must be the test suite that had the error.
Marlyn dug into the Python script which drove their tests, and found the get_num_archs
function, which theoretically would detect how many architectures this branch should output. Unfortunately, its implementation was straight out of XKCD.
def get_num_archs(self):
return 7 # FIXME
At least they left a comment.
Метки: CodeSOD |
CodeSOD: Tranposing the Key |
Russell F sends us this C# "fuction", and I have to be honest: I have no idea what it's supposed to do. I can trace through the logic, I can see what it does, but I don't understand why it does it.
private List Tranpose(List laborService )
{
int half = (int)Math.Ceiling((decimal)(laborService.Count)/2);
for (int i = 0; i < laborService.Count; i++)
{
if (i < half)
laborService[i].Order = 2 * i;
else
laborService[i].Order = (i - half) + 1;
}
return laborService.OrderBy(x => x.Order).ToList();
}
So this starts by finding the rough midpoint of our list. Then we iterate across each element, and if it's position is less than half, we place double its index into the Order
field. If it's half or greater, we store its index minus half, plus one, into its order field. Finally, we sort by Order
.
Now, based on the name, we can assume this was inspired by a matrix transposition- oh, I'm sorry, tranposition- based on the method name. It isn't one. It's almost an interleaving operation, but it also isn't one of those.
You can play with the code or just look at this table.
Ceiling of half of 10 is 5.
Indexes: 0 1 2 3 4 5 6 7 8 9
Values: A B C D E F G H I J
Order: 0 2 4 6 8 1 2 3 4 5
-----------------------------
New Sort: A F B G H C I J D E
What you can notice here is that as we re-number our Order
s, the bottom half gets doubled, but the top half increases incrementally. This means that we end up with ties, and that means that we end up with sections where elements from the either half of the list end up next to each other- see G, H
, I,J
and D, E
in my example.
What is this for? Why does this exist? Why does it matter? No idea.
But Russell has another detail to add:
The Order field is never used anywhere but in this one function -- it appears to have been added solely to allow this.
Метки: CodeSOD |
CodeSOD: Utility Functions |
As a personal perspective, I don't tend to believe that mastery of a programming tool is nearly as important as mastery of the codebase and problem domain you're working on. But there are some developers who just don't want to learn the codebase or what other developers are doing.
Take Jessica's latest co-worker, which is similar to some previous co-workers. In this case, there was a project in flight that was starting to fall behind schedule. Management did what management does in this situation: they threw warm bodies at the project and ensured that it fell further behind.
Brant was one of those warm bodies, and Brant did not want to learn what was already in the code base. He was going to do part of the JavaScript front end, he was going to rush to get it done, and he was going to copy-paste his way through.
Which lead to this:
function setMailingsReceivedCountLabel(e)
{
// Implement sting prototye format so that we can use string token replacement
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
}
// Get values
var recordCount = $("#mailingsGrid").data("kendoGrid").dataSource.total();
$("#Mailings_Count").text("(" + recordCount + ")");
}
Now, a format
method for strings is a useful function. It's not wrong to implement your own- you can't rely on template literals being supported by every browser. In fact, it's such a useful function that Jessica and the team had already added one in a generic file of utility functions. A more robust one, coupled with some unit tests, and y'know, the one you should use.
Brant had no interest in learning that there was already a function which did what he needed, so instead he implemented this one. In fact, he copy-and-pasted this blob into any method he wrote that might potentially do any sort of string formatting. I stress "might potentially", because as you can see, this method doesn't actually use his format
method.
Метки: CodeSOD |
Error'd: Not So Smart After All! |
"Today I learned that the time between 12 PM and 1 PM is "12:28 noon" according to CNN," Drew W. writes.
Robert L. wrote, "The Trump campaign website is a little bit confused as to when election day is."
"I changed over to playing on my Nintendo Switch from watching Netflix on my so-called 'smart' TV and apparently, the subtitles didn't get the message," writes Josh.
"You know how after watching a really scary horror movie, bumps in the night can leave you feeling on edge?" Matia W. wrote, "Well, seeing error messages popping up while watching a show about professional hackers is a little bit like that."
Eric L. writes, "Raising the capital for any of these seems like a pain. Yeah...I'll pass."
Метки: Error'd |
CodeSOD: Frist Item |
In .NET, if you want to get the first item from an IList
object, you could just use the index: list[0]
. You also have a handy-dandy function called First
, or even better FirstOrDefault
. FirstOrDefault
helpfully doesn’t throw an exception if the list is empty (though depending on what’s in the list, it may give you a null).
What I’m saying is that there are plenty of easy, and obvious ways to get the first element of a list.
Stevie’s co-worker did this instead:
IList orderList = db.GetOrdersByDateDescending().ToList();
int i = 1;
foreach (Order order in orderList)
{
if (i == 1)
{
PrintOrder(order);
}
i++;
}
So, for starters, GetOrdersByDateDescending()
is a LINQ-to-SQL call which invokes a stored procedure. Because LINQ does all sorts of optimizations on how that SQL gets generated, if you were to do GetOrdersByDateDescending().FirstOrDefault()
, it would fetch only the first row, cutting down on how much data crosses the network.
But because they did ToList
, it will fetch all the rows.
And then… then they loop over the result. Every single row. But they only want the first one, so they have an if
that only triggers when i == 1
, which I mean, at this point, doing 1-based indexing is just there to taunt us.
Stevie adds: “This is a common ‘pattern’ throughout the project.” Well clearly, the developer responsible isn’t going to do something once when they could do it every single time.
Метки: CodeSOD |
Announcements: What The Fun Holiday Activity? |
The holidays are a time of traditions, but traditions do change. For example, classic holiday specials have gone from getting cut down for commercials, to getting snapped up by streaming services. Well, perhaps it's time for a new holiday tradition. A holiday tradition which includes a minor dose of… WTF.
We're happy to announce our "Worse Than Failure Holiday Special" Contest. This is your chance to submit your own take on a very special holiday story. Not only is it your chance to get your place in history secured for all eternity, but also win some valuable prizes.
We want your best holiday story. Any holiday is valid, though given the time of year, we're expecting one of the many solstice-adjacent holidays. This story can be based on real experiences, or it can be entirely fictional, because what we really want is a new holiday tradition.
The best submissions will:
Are you going to write a traditional story? Or maybe a Dr. Seussian rhyme? A long letter to Santa? That's up to you.
Submissions are open from now until December 11th. Use our submission form. Check the "Story" box, and set the subject to WTF Holiday Special
. Make sure to fill out the email address field, so we can contact you if you win!
The best story will be a feature on our site, and also receive some of our new swag: a brand new TDWTF hoodie, a TDWTF mug, and a variety of stickers and other small swag.
The 2 runners up will also get a mug, stickers and other small swag.
Get writing, and let's create a new holiday tradition which helps us remember the true meaning of WTFs.
https://thedailywtf.com/articles/what-the-fun-holiday-activity
Метки: Announcements |
CodeSOD: When All You Have Is .Sort, Every Problem Looks Like a List(of String) |
When it comes to backwards compatibility, Microsoft is one of those vendors that really commits to it. It’s not that they won’t make breaking changes once in awhile, but they recognize that they need to be cautious about it, and give customers a long window to transition.
This was true back when Microsoft made it clear that .NET was the future, and that COM was going away. To make the transition easier, they created a COM Interop system which let COM code call .NET code, and vice versa. The idea was that you would never need to rewrite everything from scratch, you could just transition module by module until all the COM code was gone and just .NET remained. This also meant you could freely mix Visual Basic and Visual Basic.Net, which never caused any problems.
Well Moritz sends us some .NET code that gets called by COM code, and presents us with the rare case where we probably should just rewrite everything from scratch.
'''
''' Order the customer list alphabetically
'''
'''
'''
Public Function orderCustomerAZ() As Boolean
Try
Dim tmpStrList As New List(Of String)
Dim tmpCustomerList As New List(Of Customer)
' We create a list of ID strings and order it
For i = 0 To CustomerList.Count - 1
tmpStrList.Add(CustomerList(i).ID)
Next i
tmpStrList.Sort()
' We create the new tmp list of customers
For i = 0 To tmpStrList.Count - 1
For j = 0 To CustomerList.Count - 1
If CustomerList(j).ID = tmpStrList(i) Then
tmpCustomerList.Add(CustomerList(j).Clone)
Exit For
End If
Next j
Next i
' We update the list of customers
CustomerList.Clear()
CustomerList = tmpCustomerList
Return True
Catch ex As Exception
CompanyName.Logging.ErrorLog.LogException(ex)
Return False
End Try
End Function
As the name implies, our goal is to sort a list of customers… by ID. That’s not really implied by the name. The developer responsible knew how to sort a list of strings, and didn’t feel any need to learn what the correct way to sort a list of objects were.
So first, they build a tmpStrList
which holds all their IDs. Then they Sort()
that.
Now that the IDs are sorted, they need to organize the original data in that order. So they compare each element of the sorted list to each element of the unsorted list, and if there’s a match, copy the element into tmpCustomerList
, ensuring that list holds the elements in the sorted order.
Finally, we clear out the original list and replace it with the sorted version. Return True
on success, return False
on failure. This last bit makes the most sense: chucking exceptions across COM Interop is fraught, so it’s easier to just return status codes.
Everything else though is a clear case of someone who didn’t want to read the documentation. They knew that a list had a Sort
method which would sort things like numbers or strings, so boom. Why look at all the other ways you can sort lists? What’s a “comparator” or a lambda? Seems like useless extra classes.
https://thedailywtf.com/articles/when-all-you-have-is-sort-every-problem-looks-like-a-list-of-string
Метки: CodeSOD |
Sweet Release |
Release Notes: October 31, 2019
"And ... send." Mark sent the weekly release notes to the distribution list, copying them from where the app itself would display them on boot. "Now everyone should be on the same page, and I can get to work on my next big feature."
Two hours later, Janine, the product manager, stopped by his cube. "Hey, Mark. I was thinking. You know that About page? I keep getting complaints. What would it take to just axe it?"
"Already done in the latest version," he replied, not even looking up from the code.
"So that's, what, three hours of work?"
Mark had to tear his eyes away from the screen to look at Janine, baffled. "Huh? No, it's done. Already. It's gone. Didn't you update this morning?"
"Oh! Already! Okay, thanks. Good work." She vanished, leaving him to reload his train of thought and focus on the refactor he was doing.
Half an hour later, just as he was in the middle of something, one of the users, Roger, dropped in. "Hey, Mark! I know this should go through Janine, but I have a great idea, and I wanted to see if it was feasible."
"Hang on ... okay ... shoot." Mark hit Ctrl-S and focused on Roger. Remember, think customer service.
"Listen," Roger said. "Every once in a while, right, I'm working on something, and someone comes by to interrupt, right?"
"Okay?" began Mark, unclear where this was going.
"And you know how it goes. One thing leads to another, and so on, and eventually, I forget what I was doing, and I close out the program."
"Sure." Mark risked a glance at his IDE, wondering if he had time to start compiling or not.
"So, what if the program saved automatically, like, when I exit or something?" Roger asked.
"Oh, actually, as of this morning it auto-saves every five minutes," Mark said.
"Okay, cool, cool, but like, it should save when I exit."
"Um, I think it asks if you want to save, but I could maybe put that—"
"Or," Roger interrupted, "better yet, it should know when I get distracted, and save then, so I don't lose anything."
"It should ... know? How would it know?"
"Eh, you're right. Maybe it should just save every ten minutes."
Mark pinched the bridge of his nose. "I can do that. What about every five?"
"Perfect! Get right on that," Roger declared, striding away. "Good man."
He'll figure it out eventually, Mark decided, going back to his IDE.
He compiled, ran the software, and was in the middle of testing when Janine came by in a panic, carrying her open laptop. "Mark! We have to roll back the release!"
He didn't wait for auto-save, but exited his debugger, immediately pulling up the release console. "What, what's wrong? What happened?"
"You know how you killed the About page?" she demanded, eyes wide with horror.
"Yeah?"
"Well the Terms and conditions were in there! Legal says we can't ship without terms and conditions! This is a huge priority-one bug, I don't know how you missed it!"
Mark's shoulders slumped as he stopped logging into the release console. "Oh. I put them under Help."
"But I told you to put them under About!"
"And then you told me to kill the About page but keep the Terms and Conditions, so I moved them under Help. Didn't you read the release notes?"
"Oh, right, right, hang on, let me just pull it up here ... oh, never mind, it's under Help. False alarm! Carry on."
So Mark carried on, one eye on the time. I barely got anything done, as usual for a Monday. I really don't want to stay late tonight ... Still, he managed to get into the flow of things, and was just refactoring a critical class when Sue, Mark's boss, stopped by. Mark of course pulled his attention away from the code to talk to the boss, though already he was beginning to resent the constant interruptions.
"Hey, Marky Mark, how's it going?" asked Sue.
"Fine."
"Good, good. Listen, I know you're busy, so I'll get right to it: we have a request from the CEO, so it'll need to get into next week's release for sure."
Feeling his odds of getting the refactor committed evaporating, Mark nodded. "All right, I'm on it. What is it?"
"So, you know how the product can send email, right?"
My least favorite feature. "Yup. What about it?"
"Well the CEO was thinking, he can do stuff in Gmail that you can't do in our product, and he wants to know why."
He wants me to replicate all of Gmail in the product?! "What things, specifically?" Mark managed to ask calmly.
"He's not super technical, but he's talking about things like bold, italics, and underlines. Those are the big three."
Mark smashed his forehead into the keyboard for a moment before lifting his head to mutter: "Why do I even send release notes?"
"What?"
"We released that feature this morning!"
"Oh. Good show! Thanks Mark, you're the best."
Just as he was packing up for the day, Janine stopped by again, knocking on the edge of his cubicle, a phone to her ear. "Mark! Listen, I've got the CEO on the phone, he wants to know where we find the autosaves, and I can't figure it out. Do you know?"
Mark looked at the clock: 5:10. "Nope!" he said cheerily. "Check the release notes, I'm sure it's in there somewhere."
"I looked, I didn't see it."
"Shame, but I'm already logged out of everything. Tell him to do a real save and we'll get back to him in the morning."
"Oh, never mind, he found it! Turns out it was in the release notes. Thanks Mark, you're a lifesaver!"
If you say so. Mark walked out the door, not bothering to reply, and headed directly across the street to the pub for his weekly Monday Evening Beer.
Six days until we start from the top, he thought.
Метки: Feature Articles |