-Поиск по дневнику

Поиск сообщений в rss_thedaily_wtf

 -Подписка по e-mail

 

 -Постоянные читатели

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 06.04.2008
Записей:
Комментариев:
Написано: 0

The Daily WTF





Curious Perversions in Information Technology


Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://thedailywtf.com/.
Данный дневник сформирован из открытого RSS-источника по адресу http://syndication.thedailywtf.com/thedailywtf, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

CodeSOD: Constantly Querying

Среда, 07 Июля 2021 г. 09:30 + в цитатник

Arguably, the biggest problem with SQL as a query language is that we usually execute SQL statements from inside of some other programming language. It tempts us into finding quick hacks to generate dynamic SQL statements, and if we do it the quick way, we find ourselves doing a lot of string concatenation. That way lies SQL injection vulnerabilities.

Constructing SQL statements by stringing together text is always a bad idea, even if you're still using query parameters. There's a reason why most modern database wrappers provide some sort of builder pattern to safely construct dynamic queries. Even so, everyone wants to find their own… special way to accomplish this.

Take this sample from Sciros:

// Submitter's note: redacted or modified domain or sensitive data (it's not originally about ordering pizza) package com.REDACTED; /** * Stores skeletal SQL statments associated with the pizza order domain. * * @author REDACTED */ public interface PizzaOrderSQL { /** * The SQL keyword to order results ascending. */ public static final String ASC_SQL_KEYWORD = "ASC"; /** * The SQL keyword to order results descending. */ public static final String DESC_SQL_KEYWORD = "DESC"; /** * The common FROM SQL clause that represents the count of records. */ public static final String RECORD_COUNT_FROM_CLAUSE = "SELECT COUNT(*) "; /** * The SQL clause to constrain pizza orders to exclude certain toppings. */ public static final String EXCLUDED_TOPPINGS_SQL_CLAUSE = " AND " + " B.TOPPING NOT IN (%s) " /* excludes test toppings */; /** * The SQL clause to constrain pizza orders by status type. */ public static final String PO_BY_STATUS_SQL_CLAUSE = " AND " + " A.STATUS_CODE IN (%s)"; /** * The SQL clause to constrain pizza orders that start at or earlier than a certain time */ public static final String PO_BY_START_TIME_AT_OR_BEFORE_SQL_CLAUSE = " AND " + " A.START_TIME <= TO_DATE('%s', 'MM/DD/YYYY HH24:MI:SS')"; /** * The SQL clause to order returned pizza orders by delivery vehicle. */ public static final String WO_ORDER_SQL_CLAUSE = "ORDER BY B.DELIVERY_VEHICLE_ID"; //... REDACTED lots of massive select and where clauses that follow the gist of those shown. }

ASC_SQL_KEYWORD is automatically funny, given that it's vastly longer than the actual keyword. But RECORD_COUNT_FROM_CLAUSE is pretty amazing, since that's a SELECT clause, not a FROM clause.

This actually gets used with string concatenation to build the queries:

string query = RECORD_COUNT_FROM_CLAUSE + PIZZA_ORDERS_TABLE_CLAUSE + PO_BY_START_TIME_AT_OR_BEFORE_SQL_CLAUSE + EXCLUDED_TOPPINGS_SQL_CLAUSE + ORDER_BY_DATE_CLAUSE + DESC_SQL_KEYWORD;

It does at least use parameters. Now, whether those parameters are actual query parameters or just printf-style string-munging, we'll… I'll give them the benefit of the doubt, because it's bad enough as it is.

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

https://thedailywtf.com/articles/constantly-querying


Метки:  

News Roundup: A Brillant Copilot

Вторник, 06 Июля 2021 г. 09:30 + в цитатник

The story of the week in software development is Github's Copilot, which promises to throw machine learning at autocomplete for a "smarter" experience.

Notably, one of their examples highlights its ability to store currency values in a float. Or to generate nonsense. Or outputting GPLed code that was used in its training set.

That last one raises all sorts of questions about copyright law, and the boundaries of what constitutes fair use and derivative works, and whether the GPL's virality can "infect" an ML model. These are questions I'm not qualified to answer, and that may not have a good answer at the moment. And certainly, the answer which applies to the US may not apply elsewhere.

Besides, copyright law is boring. What's fun is that Copilot also spits up API keys, because it was trained on open source projects, and sometimes people mess up and commit their API keys into their source control repository. Oops.

And even their examples don't really constitute "good" code. Like their daysBetweenDates, straight from their website:

function calculateDaysBetweenDates(date1, date2) { var oneDay = 24 * 60 * 60 * 1000; var date1InMillis = date1.getTime(); var date2InMillis = date2.getTime(); var days = Math.round(Math.abs(date2InMillis - date1InMillis) / oneDay); return days; }

Now, this code is fine for its stated task, because JavaScript has absolutely garbage date-handling, and developers are forced to do this themselves in the first place. But it's barely fine. A solution copy-pasted from StackOverflow that fails to hit the "single responsibility principle" for this method (it calculates the difference and converts it to a unit of time- days, in this case). It's not WTF code, sure, but it's also not code that I'd give a thumbs up to in a code review, either.

And it also ignores the right answer: use a date handling library, because, outside of the most limited cases, why on Earth would you write this code yourself?

Or this code, also from their website:

function nonAltImages() { const images = document.querySelectorAll('img'); for (let i = 0; i < images.length; i++) { if (!images[i].hasAttribute('alt')) { images[i].style.border = '1px solid red'; } } }

img:not([alt]) is a query selector that would find all the img tags that don't have an alt attribute. You could go put it in your stylesheet instead of directly modifying the style property on the element directly. Though the :not pseudo-class isn't available in IE6, so that maybe makes my solution a non-starter.

I'm not picking on some tech-preview tool that's still working the kinks out, here. A human being looked at these examples and decided that it's a good way to demonstrate the power of their new tool. Presumably a group of people looked at this output and said, "Yeah, that's the stuff, that feels like magic." Which brings me to my real point.

Any ML system is only as good as its training data, and this leads to some seriously negative outcomes. We usually call this algorithmic bias, and we all know the examples. It's why voice assistants have a hard time with certain names or accents. It's why sentencing tools for law enforcement mis-classify defendants. It's why facial recognition systems have a hard time with darker skin tones.

In the case of an ML tool that was trained on publicly available code, there's a blatantly obvious flaw in the training data: MOST CODE IS BAD.

Here at TDWTF, we try and curate the worst of the worst, because observing failure is often funny, and because we can also learn from these mistakes. But also: because this is also us. We've all written bad code at some point, and we're all going to write bad code again. We tell ourselves we'll refactor, but we never do. We make choices which make sense now, but in six months a new feature breaks our design and we've gotta hack things together so we can ship.

Most of the code in the world is bad.

If you feed a big pile of Open Source code into OpenAI, the only thing you're doing is automating the generation of bad code, because most of the code you fed the system is bad. It's ironic that the biggest obstacle to automating programmers out of a job is that we are terrible at our jobs.

In any case, I hope someone scrapes TDWTF and trains a GPT-3 model off of it. We can then let the Paulas of the world retire.

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

https://thedailywtf.com/articles/a-brillant-copilot


Метки:  

Classic WTF: Consultants of the Crystal Citadel

Понедельник, 05 Июля 2021 г. 09:30 + в цитатник
It's a holiday weekend in the US, so we turn back to 2009, and explore the Crystal Citadel. Don't worry, there's a flow chart. -- Remy

Photo Credit: 'Thristian' @ FlickrIt was the mid-1990's and business was booming at the company that Terry worked at. It was booming so much that the existing process of entering an order — faxing in an order form torn out of an outdated-as-soon-as-it-was-printed catalog — was delaying things enough that it was costing the company some serious dough in missed sales. Needing a way to re-engineer the process without hiring an army of support staff, management decided on an innovative plan that would enable customers to place orders electronically without needing to contact customer service.

With resources being tight (even the help desk was fielding order inquiries), management decided to farm out the work to an outside IT firm. Now, important work like this wasn't going to be farmed out to the boss's nephew who was a whiz at programming in Word and Excel. Instead they were going with a big name, "we named our building after ourselves" company. Yes it would be expensive, but the money that could be saved by receiving orders this new way would allow the program to more than pay for itself in short order.

Terry, a senior developer for the existing inventory ordering system, acted as a liason between his company and the technical manager who oversaw a team of consultants at the firm.

The initial meetings to define requirements went ok. Terry had done his homework and came prepared with screen mockups and specs of how to hook into their existing system. During the meetings, the Project Manager and Technical Lead would reply with head nods and the occasional "Um-hm...yes, this is doable...um-hm". The estimates came back and Terry's company provided the capital to get everything going. Everything appeared to be humming along fairly smoothly.

Soon, the consultants were ready to deliver the fruits of their labor. In the final meeting, the Project Manager went on about how the application would "maximize positive customer synergies" and provide "value added cross-functional, intra-business combinations". Through the marketing mumbo-jumbo, Terry was happy when he saw two things - the UI looked good and the application (though working against a set of test data) seemed to run smoothly. The consultants delivered the code and Terry was on his way.

Under the Hood

As a cost saving measure, Terry's company planned to start with with a much-simplified version of what they actually wanted. By starting out with code developed by a top-notch IT firm, any flaws or minor enhancements could be easily tweaked. Plus, it just cost less for a salaried developer to make a data field label in italics or move a button a few pixels. A month or two, tops, of polishing up would make it shine out as being a crown jewel for Terry's company and save them millions.

At first glance of the source, Terry thought that the application must have been written by gurus placed so high in that crystalline building of theirs that their logic transcended that of mere humans. They were very expensive, were prominantly placed, and therefore the best...right?

Instead, upon further review, the end product that Terry only had to "polish up" was more likely a result of the developers not getting enough oxygen in that high rise of theirs. Following is how the order process worked.

Aftermath

Once the inner workings of the program were explained to management, the project was scrapped in favor of implementing a simple PDF catalog on CD where a customer would fill out a paper form and fax it into the order processing center where it would be hand entered. It is hoped that by not having to print paper catalogs that the six figure cost of development can be recovered ...eventually.

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

https://thedailywtf.com/articles/classic-wtf-consultants-of-the-crystal-citadel


Метки:  

Error'd: The Past is Prologue

Пятница, 02 Июля 2021 г. 09:30 + в цитатник

Last week we lightly brushed on the novel conspiracy theory that perhaps the HBO hullabaloo had been intentionally inspired by their social media team, and suggested you might join them. Apparently the media managers at Subway had been hungering for publicity as well.

TDWTF sandwich specialist Carlos buttered us up, saying "I'm sure you've received a ton of these already [ed: we hadn't], but what's one more?"

subway

 

TDWTF super-sleuth Samji stumbled upon some school student's summer take-home project, it seems. Her temperature conversion is comic but as Samji astutely points out, "F to C++ would be even weirder." The extremely amateur nature of this site raises more questions than it answers, chief among them being "why?"

wtc

 

Washed-up refugee Sebastian, reluctant to join Subway's test-automation-in-production, discovers that the opportunities for his own favored style of work are scarcer than hen's teeth. "I've been looking around, but I guess McKinsey really doesn't like automation jobs."

jobs

 

While his compatriot Antonio, searching for warranty repair, bemoans the slow service: "If I'll be waiting this long for an LCD, you might as well send a fresh battery too". He really should be looking at Dell in the (very near) future.

warranty

 

Near-future historian Samuel H. warns "Watch out Amazon, Dell can now deliver before they ship." Give them time, and they'll be delivering before you order!

future

 

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

https://thedailywtf.com/articles/the-past-is-prologue


Метки:  

CodeSOD: Echo echo echo echo

Четверг, 01 Июля 2021 г. 09:30 + в цитатник

Good logging is an invaluable tool for debugging and diagnosing your applications. No logging makes that job harder, but not as hard as bad logging. Logging that doesn't log useful information, that doesn't help highlight the flow of the application, etc.

Volker was trying to track down a bug that was only raising its head in production, but the log files were spammed with nothing more than "echo". Millions and millions of log lines that were just that. A quick CTRL+F through the code later, and the offending method was found:

public int getEcho(){ System.out.println("echo"); return 1; }

This was clearly some sort of sanity check method, a heartbeat or something. It was almost certainly added early, and never meant to actually end up in production. Like so much code that was never meant to end up in production, though, this did. And for years, it'd been churning away, "echo"ing into the night. Other developers had looked at the logs. Other developers had seen the echo. No one had bothered to fix the problem, however.

Worse, this method was only called in one place: an overloaded toString method in the base class for all the application's domain objects. Nearly every object got converted to a string at some point, because an important job of the application was to convert collections of domain objects into lovely HTML emails. That simple description, I suspect, conceals a lot of other WTFs.

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/echo-echo-echo-echo


Метки:  

CodeSOD: Repository, Man

Среда, 30 Июня 2021 г. 09:30 + в цитатник

C++ templates are, notoriously, a Turing complete language on their own. They're complicated, even when you're trying to do something simple. Related languages avoid that complexity, and favor generics. Generics are templates with all the sharp bits filed down, but still powerful enough to make datastructures that don't need to know the details of the data they're operating on.

This article isn't about generics, though. It's about ORMs, specifically the .NET Entity Framework system. It's common to use the Repository Pattern to abstract out data access a bit. Coupled with the underlying DBSet class, which roughly represents a database table, you can easily create repository objects and related mocks for testing.

Making your repository class generic is also a good idea. Basic CRUD operations don't really need to know the details the data they're operating on. You can create one repository instance for each type of data you need to store- each table- all based on the same generic type.

But it's possible to make your repository too generic. Take Paulina's company. Here's a few key lines from their generic repository.

public class Repository<T> : IRepository<T>, IDisposable { MasterContext context = new MasterContext(); // MasterContext derives from Entity Framework's DbContext public void SaveEntity<T>(T entity) where T : class { context.Set().Add(entity); context.SaveChanges(); } public void UpdateEntity<T>(T entity) where T : class { context.Set().Attach(entity); context.Entry(entity).State = System.Data.EntityState.Modified; context.SaveChanges(); } public void DeleteEntity<T>(T entity) where T : class { context.Set().Attach(entity); context.Entry(entity).State = System.Data.EntityState.Deleted; context.SaveChanges(); } public IQueryable<T> Entities<T>() where T : class { return context.Set().AsQueryable(); } // … }

The first suspicious thing is MasterContext. Deriving from the built-in DbContext is a code smell- you should wrap the DbContext in your own functionality, not extend it.

The real "gotcha" in this, however, is the method definitions. Not only is the class itself generic, but each of its methods is also generic. This creates an odd scenario, where you could do something like this:

var carRepo = new Repository(); carRepo.SaveEntity(new Driver());

The repository isn't actually specific to a type. That's not exactly a disaster, but it certainly makes the code more confusing to use. So much more confusing that folks within the organization don't like this version of type safety. So this base Repository class is seated at the base of an inheritance tree.

Derived from Repository is GenericCrudRepository. From that is derived an ExtendedGenericCrudRepository. Then, for any given data entity that we want to save, there are specific types- CarRepository or DriverRepository. Many generic methods are essentially re-implemented with concrete types slotted in, meaning all of these child classes are just piles of similar methods with different calling semantics that all basically do the same thing.

The end result is an incredibly complex and confusing data-access layer. And it's worth noting that the main benefit of a Repository is that it theoretically makes your code more testable, which ah… you'd be surprised to note that since all the repository instances are concrete classes deep down the inheritance tree, they're referred to by specific type and not by interface, meaning no one actually mocked them, and any code that wraps around the database goes untested.

Oh, and this isn't one application. This is a generic data access framework used by every software product in their organization.

Pauline writes: "You can imagine that these projects are very expensive to maintain."

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/repository-man


Метки:  

CodeSOD: Big Number One

Вторник, 29 Июня 2021 г. 09:30 + в цитатник

Patsy's company has a product that's "number one" in their particular industry. It generates lots of revenue, but a lot of the code dates back to the far-off year of… 2017. Coding practices were… uh… different, four years ago? Especially in the rapidly maturing language of… Java?

Within Patsy's company, they do refer to their 2017 code as "legacy" code, and it has left quite the legacy. For example, here's how they parse numbers:

public BigDecimal parseNumberInString(String content) { // variables for (int i = 0; i < content.length(); i++) { if (Character.isDigit(content.charAt(i))) { numbers.append(content.charAt(i)); } else if ((content.charAt(i) == DOT || content.charAt(i) == SPACE || content.charAt(i) == COMMA) && numbers.length() > 0) { //is it a decimal separator? if not, ignore, if yes append "." if ( (content.length() == (i + 2) && (Character.isDigit(content.charAt(i + 1)))) || (content.length() >= (i + 2) && (Character.isDigit(content.charAt(i + 1))) && lastDecimalFound!=null && !lastDecimalFound.equals(content.charAt(i))) || (content.length() == (i + 3) && (Character.isDigit(content.charAt(i + 1)) && Character.isDigit(content.charAt(i + 2)))) || (content.length() > (i + 3) && (Character.isDigit(content.charAt(i + 1)) && Character.isDigit(content.charAt(i + 2)) && !Character.isDigit(content.charAt(i + 3)))) || (content.length() > (i + 2) && (Character.isDigit(content.charAt(i + 1)) && !Character.isDigit(content.charAt(i + 2)))) || (content.length() > (i + 4) && (Character.isDigit(content.charAt(i + 1)) && Character.isDigit(content.charAt(i + 2)) && Character.isDigit(content.charAt(i + 3)) && Character.isDigit(content.charAt(i + 4)))) || (lastDecimalFound==null && content.length() == (i + 4) && (Character.isDigit(content.charAt(i + 1)) && Character.isDigit(content.charAt(i + 2)) && Character.isDigit(content.charAt(i + 3)) && content.charAt(i)==decimalMark)) || (lastDecimalFound==null && content.length() > (i + 4) && Character.isDigit(content.charAt(i + 1)) && Character.isDigit(content.charAt(i + 2)) && Character.isDigit(content.charAt(i + 3)) && content.charAt(i)==decimalMark && !Character.isDigit(content.charAt(i + 4)) && (content.charAt(i+4) != COMMA) && (content.charAt(i+4) != DOT)) ) { numbers.append('.'); } lastDecimalFound=content.charAt(i); } else if (content.charAt(i) == DASH && numbers.length() == 0) { //probably a negative sign numbers.append(content.charAt(i)); } else if (numbers.length() > 0) { //we found some other characters and already have a number parsed, so quit break; } } // … snip }

Obviously, as this is "legacy" code, you couldn't rely on Java having a built-in method to parse numbers. And this worked, at least, though comments like "probably a negative sign" aren't exactly going to inspire confidence.

It's ugly, it's complicated, and it only supports two significant figures behind the decimal place, which is where the trouble actually starts. Customers started to want to use more precision, going out to three decimal places.

Well, that's a reasonable feature, and since this was legacy code anyway, it was a great opportunity to rewrite the function. Which is exactly what one of Patsy's co-workers did.

public BigDecimal parseNumberInString(String content) { // variables for (int i = 0; i < content.length(); i++) { if (Character.isDigit(content.charAt(i))) { numbers.append(content.charAt(i)); } else if (content.charAt(i) == DOT && lastDecimalFound == null){ //parse first dot encountered, ignore rest lastDecimalFound=content.charAt(i); numbers.append('.'); } else if ((content.charAt(i) == DOT || content.charAt(i) == SPACE || content.charAt(i) == COMMA) && numbers.length() > 0) { continue; } else if (content.charAt(i) == DASH && numbers.length() == 0) { //probably a negative sign numbers.append(content.charAt(i)); } else if (numbers.length() > 0) { //we found some other characters and already have a number parsed, so quit break; } //… snip } }

This fixed the three decimal places problem, but wouldn't you know it, their users in Europe keep complaining about it incorrectly parsing numbers. Maybe someday they'll find a way to fix that issue too, if it's even possible to parse numbers in locale-specific formats. If only such a thing were possible.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/big-number-one


Метки:  

CodeSOD: Out of You and Umption

Понедельник, 28 Июня 2021 г. 09:30 + в цитатник

When we write code, we have certain assumptions. Most of these times, these assumptions are fine, and allow us to skip past some hard decisions. But sometimes, these can lead to problems. The infamous example would be the Y2K problem- the assumption that nobody'd be running this program in 40 years seemed reasonable at the time. We might assume that nobody'd type too fast. We might assume our sensor is accurate.

Darren sends us some code that has a much milder assumption than those:

Assert(false, 'Contact ANTHONY if you get this error');

The assumption here was that Anthony's employment would last longer than this code did. That was not true. It's legacy code, so there's no meaningful commit history that far back, there's no documentation or comments, and no one now at the company ever remembers an Anthony working there. No one knows why this error needs Anthony, no one knows what Anthony would do if this error was brought to his attention, and no one knows when the last time this error happened anyway.

To poetically paraphrase:

And in the codebase, these words appear:
"Contact ANTHONY if you get this error"
Nothing beside remains.

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

https://thedailywtf.com/articles/out-of-you-and-umption


Метки:  

Error'd: Production Testing To The Max

Пятница, 25 Июня 2021 г. 09:30 + в цитатник

The most eventful day in Error'dland narrowly missed our publication window last week. As everyone must surely know by now, somebody at HBO Max was testing in production. And the Internet blew up.

reddit

And our inbox blew up.

inbox

Naturally, the social media team at HBO decided to try and capitalize on the kerfluffle with a bit of light-hearted brand action, because of course they did:

intern

In turn spawning an angry Twitter mob (because of course it did) excoriating HBO for mistreating the poor schlub, a global We Are Spartacus moment, and alack, a new conspiracy theory because, alas, of course it did. It just wouldn't still be 2020 without a new conspiracy theory.

conspiracy

This all goes to show that test-in-prod can be good for business. As long as you can avoid the sickest errors like this one that our friend Brian B. uncovered. He wrote "Our daily health screening provider was supposed to ask if you've had a COVID-19 vaccine. Yes/No/Postpone/Decline. This is what we got on the first day. I guess the entire SQA team is in quarantine."

brian

 

So when you decide to run a test in production, don't be boring like these EBay sellers that bargain-hunter David found:

boring

 

Instead, lean into it! Immanentize the conspiracies! Get your Marketing department and social media team involved! Tell them you want to do something viral and fabulous! Like this beret'd beagle stuffed stormtrooper steed. Good Luck.

froggy

 

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/production-testing-to-the-max


Метки:  

Classic WTF: Front-Ahead Design

Среда, 23 Июня 2021 г. 09:30 + в цитатник
Summer breaks are a great opportunity to improve yourself. And what's a better way to use your summer break than to take some high end certification training. Prove that you're ready for the FAD! Original --Remy

In the past, I didn’t mix TDWTH and work too often, but with the tweaked name and tweaked direction on content, I knew this article would be a perfect fit.

As some of you know, I fill two important roles in my day job at Inedo, LLC. Not only am I a software developer, but I’m also the Chief Front-Ahead Design Evangelist. In this latter role, it’s my duty to spread and champion the revolutionary software development methodology known as Front Ahead Design (FAD).

If you’re not familiar with FAD, then you’ve been missing out. Essentially, FAD is a fundamental paradigm shift over the “traditional” and “neo” ways of building software. Not only does it surpass every other software development methodology out there, it solves every problem there is to building software. And then some.

The FAD Manifesto

I. Front Ahead Design
The essence of FAD is conveyed directly in its name: design your front-end/user-interface first, ahead of everything else. The customer could care less what’s behind the scenes, so long as it looks good and does what it’s supposed to. Deliver a working front-end first and then Do What It Takes to fill in the functionality gaps.

II. Do What It Takes
Other methodologies are great at delivering excuses. How many times have you heard (or have been told) “we can’t do that here because it could throw off the whole design?” In FAD, you just do it (that would have been the bullet point, but Nike has it trademarked). To get it done, you Do What It Takes. Your customer will love you.

III. Code Light, Not “Right”
A traditional methodology calls a complex framework with layer after layer of objects. In those ways, adding a simple value to a form can be a monumental task, requiring it to be added to every single layer. Does that sound right? Proponents of the other methodologies will tell you it is, but what about your customer? With FAD, you just Do What It Takes to add the functionality to your interface. No more.

IV. “Throw Away” Diagrams
Think of all the Visio diagrams you’ve drawn over the years. Sequence diagrams, context diagrams, flow charts, and so on. Was that really productive? Did your customer ever see any of those? Were those diagrams even relevant after the system was finally developed? Didn’t think so.

In FAD, all diagrams are made on a disposable medium. Whiteboards, napkins, even your forearms work. And there is no formal modeling language to battle with: just Do What It Takes to draw and explain your design to other developers.

V. Life Is Short (a.k.a. Patchwork)
The average software system has a life expectancy of seven years. No matter how “properly” the system is designed from the start, within the first year of its life, maintenance programmers unfamiliar with the complex architecture (and having no help from out-of-date documentation) will turn the system into a complete mess with bug fixes and change requests.

In FAD, this isn’t even a concern. We know the short life span of a system and develop every feature (from the interface) as a patch. Maintenance programmers can come in and Do What It Takes to add their patches. In FAD, we don’t even try to stop the aging process. We encourage it.

VI. Learn To Deal
Many other methodologies focus on delivering “quality” (as in “bug free”) software. And guess what: they fail. Miserably. No matter how hard you try, software will have bugs. In FAD, we just learn to deal with it, and we encourage the client to do the same. So what if the application crashes when you click that button that way? Don’t click the button that way, and learn to deal!

VII. Be Environmentally Conservative
In the real world, there’s only one environment: it’s called The Real World. So why do some methodologies invent these counter-intuitive, bizarro environments called “QA” and “UAT”? Do architecture firms construct an entire house before building an addition on yours, just so they can “test” their building skills? Of course not, and neither should software developers. In FAD, there’s only one software environment: Production. Anything else is pollution.

FAD Application Design

NOTE: First and foremost, understand that the FADAD is merely the preferred method of building applications. Because in FAD, we do what it takes, a lesser or more in depth approach can be used as needed.

Many of the tenets of Front Ahead Design are based on the failings of other methodologies. FADAD is no different, and draws some of its key facets from the archaic Model-View-Controller architecture. In MVC, there are three different components: the Model (the data), the View (the UI), and the Control (everything else).

If you think about it, two of MVC’s components are nothing but dead weight. All anyone – including the client – really cares about when all things are said and done is the View. Therefore, in FADAD, our guiding architecture model is simply called “V”:

The H/YPE Framework: The FAD Developer’s Best Friend

If there’s one thing that’s frustrated just about every developer out there, it’s “untouchable” library code that almost does what you need it to, but not quite. For FAD developers who chose to use the H/YPE framework, this is not a problem.

Unlike the stodgy libraries of yesteryear, H/YPE is not a “compiled” library. It’s a set of cross-language codefiles that can be copied to any application, and is designed to “live” with that application for life. Don’t like that 48 plus 92 is not 4892? No problem! Just edit MathHelper. Here’s a small subset of what comes in H/YPE:

  • HYPE.StringHelper – all sorts of functions like IsEqual, AreEqual, Add, Subtract, Join, DoubleJoin, Encrypt, and Decrypt
  • HYPE.VHelper.HTML – the ultimate HTML library including functions like WrapInCENTER, UnHTML, ToHTML, and ScriptBlock
  • HYPE.Audio – everything you’d ever want to add audio, including Beep and BeepMore

But Wait, There’s More: Certification!

No, I don’t mean to sound like our good friend Ron Popeil, but before wrapping things up here, I wanted to tell you about the latest excitement in the world of Front-Ahead Design: certification!

Just last week at the International FAD Conference in Azerbaijan, I joined several other FAD leaders to formally announce the first official Front-Ahead Design certification program: the Fadstronaut certificate. Why Fadstronaut? Because we felt that the astronaut was the best analogy for the challenges and difficulties that FAD software developers face each day.

Becoming a Certified Fadstronaut is easy, but not too easy. All you need is one year (1,000 hours) of verifiable FAD development experience, and you’ll be eligible to sit for the Fadstronaut certification exam. Score in the 50th percentile, and you’ve earned the designation Certified Fadstronaut!

I hope that gives you all a good idea of what FAD is all about. Believe me, there’s a whole world more of FAD out there. That said, I hope to see some of you soon at the Worldwide FAD Meeting in Buenos Aires next month!

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/classic-wtf-front-ahead-design


Метки:  

Classic WTF: Gaming the System

Вторник, 22 Июня 2021 г. 09:30 + в цитатник
Our summer break continues. For some people, summer means outdoor fun. If, like me, you hate sun and temperatures above "chilly", it can instead mean air-conditioned indoor fun. And it's all fun and games until someone loses their job. Original. -- Remy

Frank slammed his axe into his co-worker's skull. Ernest grunted and raised his double-barreled shotgun in reply. "Merry Christmas!" he shouted as he fired both barrels. Frank exploded into several gore-colored polygons.

"Jerk," Frank grumbled as he waited for his respawn. It was late Decemeber, 1997, an era of before thumb-drives and when Quake was the best deathmatch money could buy. Normally, such lunch-time and break-time violence was frowned upon, but it was the holidays. When most of the office is on vacation, and the people that aren't just need to keep the lights on and not make trouble, you can get away with those sorts of things, so long as you uninstall it after the New Year. They Quaked away through the holidays.

Months later, the Auditor swooped down onto their floor. He arrived cloaked in darkness, and paperwork clouded his footsteps. His sign was a red floppy disk and the odor of rotting roses. "I'm here," he announced, "to check for unauthorized software."

Guided by the dark god of Audit Compliance, the Auditor started with Ernest's desk. He ordered Ernest to stand aside, inserted the floppy disk, and rebooted the machine. The machine booted from the disk, churned through the hard drive, and popped up a series of messages. "MALWARE DETECTED - INFRACTION LOGGED TO a:\audit001.log."

Ernest's stomach churned when he realized that the infraction was Quake. "Unauthorized Software" was a serious offense, but having games installed had sent people to the unemployment line. Ernest watched everything the Auditor did through a veil of terror, and started thinking about how to brush up his resume.

"Thank you for your time," the Auditor said.

Ernest wasn't the only one that had forgotten. The Auditor worked up one side of the aisle of cubes, and then started back down the other. Several groans and, "That isn't mine!" protests announced his victims. Ernest cast about, and saw Frank's cube right behind him. The Auditor was a few desks away.

Ernest rang Frank's phone. In a harsh whisper, he said, "Don't turn around. Share your floppy drive."

Frank turned around and stared at Ernest, even as he whispered into the phone. "What? Why?"

"I'm going to fix the audit."

"What?" Frank raised his voice and Ernest winced. "What?" he repeated, more quietly. "Use somebody else's drive. I actually cleaned out my disk, just like I was supposed to. I'm not getting fired for you."

"You aren't going to get fired," Ernest promised. "Don't do it for me. Do it for Dave, and Chris. Do it for John Carmack."

"Fine." Frank rolled his eyes and hung up.

Ernest quickly mapped the drive from a DOS prompt. As the Auditor stalked into Frank's cube, Ernest typed format x: /Q. He stared at the screen, carefully watching the faint reflection of Frank's cube. His ears strained to hear the "chunk" of the computer accepting the disk.

As soon as he heard it, Ernest slammed the enter-key. Even as the Auditor grabbed the mouse to shut-down the machine, Ernest saw Frank's floppy drive activity light shine. As the Auditor started the reboot, Ernest saw the best words he had ever seen appear on his own screen: Format Complete.

Nothing was actually deleted by the quick format. A quick run through with a recovery tool could easily fix it. Frank played dumb, and for the Auditor it came naturally. He sat with Frank for twenty minutes, absolutely convinced that Frank's floppy drive was non-functional. Eventually, he agreed that his disk was no good and tossed it out. "I'll be back," he warned. "And we'll have to start the audit all over again."

Ernest cleaned up his computer, and smiled, confident that his job had been saved. Unfortunately, a week later, it was revealed that the audit had been little more than an attempt to shrink the department down before everyone was laid off. Their twenty-person IT staff could be replaced by twenty people in Bangalore for a fraction of the cost. But a few lucky souls, like Ernest and Frank, were retained for an extra two months to oversee the transition. It provided them plenty of time investigate the newly released Quake II.

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

https://thedailywtf.com/articles/classic-wtf-gaming-the-system


Метки:  

CodeSOD: Classic WTF: The Great Code Spawn

Понедельник, 21 Июня 2021 г. 09:30 + в цитатник
We're taking a little summer break this week for our regular articles. Since we're re-using articles, let's start with one about developer efficiency. Why write code when you can automate writing code? Original -- Remy

Several years ago, Dan D’s predecessor, Steve, came to the realization that many of us arrived at one point or another: writing data-access code can get boring and repetitive. To ease the tedium, Steve did what many developers in his position do. He wrote some code to generate a lot of code.

Unfortunately, Steve’s coding skills weren’t all too hot. Worse were his code-writing-code writing skills. In the years since The Great Code Spawn (as it has come to be known), the data-access layer has become an unmaintainable disaster – so much so that, rather than add a new database column, developers have “split” single fields into multiple through bit-shifting and string manipulation.

Following is a single line of code (re-formatted by yours truly) that represents “one of the smaller” insert statements.

new OdbcCommand(new StringBuffer()                                                           
    .append(new StringBuffer()                                                                  
     .append(new StringBuffer()                                                                 
      .append(new StringBuffer()                                                                
       .append(new StringBuffer()                                                               
        .append(new StringBuffer()                                                              
         .append(new StringBuffer()                                                             
          .append(new StringBuffer()                                                            
           .append(new StringBuffer()                                                           
            .append(new StringBuffer()                                                          
             .append(new StringBuffer()                                                         
              .append(new StringBuffer()                                                        
               .append(new StringBuffer()                                                       
                .append(new StringBuffer()                                                      
                 .append(new StringBuffer()                                                     
                  .append(new StringBuffer()                                                    
                   .append(new StringBuffer()                                                   
                    .append(new StringBuffer()                                                  
                     .append(new StringBuffer()                                                 
                      .append(new StringBuffer()                                                
                      .append("Insert into wc_scanbol values(")                                 
                      .append(num)
		      .ToString())                                                  
                     .append(",'")
		     .ToString())                                                  
                    .append(bol.BolNum)
		    .ToString())                                             
                   .append("',")
		   .ToString())                                                    
                  .append(Integer.parseInt(bol.get_ShipDate().ToString("yyyyMMdd")))
		  .ToString())
                 .append(",")
		 .ToString())                                                       
                .append(bol.Period)
		.ToString())                                                 
               .append(",'")
	       .ToString())                                                        
              .append(bol.Consignee.Replace("'", "''"))
	      .ToString())                             
             .append("',")
	     .ToString())                                                          
            .append(bol.Cases)
	    .ToString())                                                      
           .append(",")
	   .ToString())                                                             
          .append(bol.Bottles)
	  .ToString())                                                      
         .append(",")
	 .ToString())                                                               
        .append(num)
	.ToString())                                                                
       .append(",")
       .ToString())                                                                 
      .append(bol.CustID)
      .ToString())                                                           
     .append(",'")
     .ToString())                                                                  
    .append(bol.State)
    .ToString())                                                              
   .append("','')")
   .ToString(), this.con)                                                       
  .ExecuteNonQuery();
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/classic-wtf-the-great-code-spawn


Метки:  

Error'd: Some Sunny Day

Пятница, 18 Июня 2021 г. 09:30 + в цитатник

Greenville resident Terry K. discovers the weather is on the fritz today. "The chanceOfTemplateFailure seems high today," says he.

weather

 

Renault driver Drew W. predicts "We have always been under a severe thunderstorm warning, and we always will be." Thursday again?

tstorm

 

Fellow motorist Robert F. blows up: "I was searching for winter tires, but by the time I got through the 22 pages of gibberish I don't need them anymore."

winter

 

Homeowner Greg sends a strong hint why Robert can make do without snow tires: "The Ecobee complication (top left) showed that my house was somewhat warmer than usual today."

hothouse

 

We don't need to wonder why, as constant contributor Pascal comes through with the astronomical explanation and a cheery prediction. We may never need snow tires again!

solar

 

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

https://thedailywtf.com/articles/some-sunny-day


Метки:  

CodeSOD: Filter Your Kwargs

Четверг, 17 Июня 2021 г. 09:30 + в цитатник

Mark's team needed someone to write a pretty straight-forward report for their Python application. It would take a set of keyword arguments, turn those into a filter, apply the filter, and get the results back.

This was implemented in two methods. First:

def set_filters_to_query(modelquery, kwargs2): filter_by = {} if 'source' in kwargs2 and kwargs2['source'] == u'': del kwargs2['source'] if 'assigned_user' in kwargs2: filter_by['assigned_user'] = kwargs2.pop('assigned_user') if 'country' in kwargs2: filter_by['country'] = kwargs2.pop('country') if 'lang' in kwargs2: filter_by['lang'] = kwargs2.pop('lang') if 'affiliate_data' in kwargs2: filter_by['affiliate_data'] = kwargs2.pop('affiliate_data') if 'source' in kwargs2: filter_by['source'] = kwargs2.pop('source') return kwargs2, filter_by

So, a few things. kwargs isn't a "reserved word" or anything, but by convention, it's meant to be used to support, well, keyword arguments, denoted by a leading **, allowing the method to be invoked set_filters_to_query(some_model, filter_one=value, filter_two=value).

In the method, it still behaves as a dictionary, but it provides a convenient way to call it.

In any case, this method does two things. It clears values out of kwargs2, and moves them into filter_by. It then returns the pair of them as a tuple. Well, three things- it utterly ignores the modelquery parameter.

This whole method is a code smell, but aside from the misuse of kwargs, there's nothing that screams "WTF". How does this get invoked?

def count_leads(kwargs, verified): kwargs2 = dict(kwargs) kwargs2, filter_by = set_filters_to_query('Lead', kwargs2) if verified: kwargs2['email_verified'] = True results = defaultdict(int) total = 0 view_by = kwargs2.pop('view_by', None) kwargs2.update(filter_by) leads = Lead.objects.filter(**kwargs2) …

Once again, we have a method that does some kwargs misuse. We also can't trust that the input is a dict (for some reason- a problem we wouldn't have if we used kwargs correctly), so we convert it into a dict then pass the result to set_filters_to_query.

Then, a few lines later, we do this: kwargs2.update(filter_by)

set_filters_to_query popped a few fields out of kwargs2 and put them in filter_by. This operation puts them right back. The only actual side effect is that we may have deleted the key source if it was an empty string.

Then finally, we call the filter, passing **kwargs2, which expands the dict back out into keyword arguments as it's clear that Lead.objects.filter was not written by the developer responsible for this code, and works the way we'd expect such a method to work.

This code was eradicated, as you'd expect, and replaced with something more reasonable and straightforward.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/filter-your-kwargs


Метки:  

CodeSOD: World Class Contracting

Среда, 16 Июня 2021 г. 09:30 + в цитатник

The time and effort needed to complete a project and the amount of time available rarely line up well. Wayne M's company found themselves in a position where what they needed to deliver and what they could deliver by the deadline simply didn't match up.

The requirements were well specified, so they bundled up a bunch of requirements for search-related functionality, and handed them off to a self-described "world class" developer working on contract.

When the developer handed off their C# code, well, there were some problems. Like the code didn't work. It didn't even compile. Even if it did compile, it was just… bad.

public string SearchText { get; private set; } public object[] Results { get; private set; } protected void Page_Load(object sender, EventArgs e) { string searchText = UrlDecode(SetSearch()); var results = Search(searchText); results = (from r in results where r.isActive select r).ToArray(); OrdersRepeater.DataSource = Results; } private string SetSearch() { SearchText = ""; if (Request.QueryString.Get("Search") != null && Request.QueryString.Get("Search") != "") { SearchText = Request.QueryString.Get("Search"); } return SearchText; } private object[] Search(string searchText) { Results = Repository.Search(SearchText, IsActiveEnum.All); Return Results; }

The cause of the compilation failure is that last return line, or should I say, Return. Which this isn't the only case of capitalization causing issues.

The goal of this code is to take the Search parameter from the URL query string, and run it through the database to find results which can then be displayed in an OrdersRepeater- a server-side UI object that generates HTML output.

The key problem and source of confusion is that there's a property SearchText, and there's a parameter in the Search method called searchText. In the Search method, the property is used for the search, not the parameter, which is just ignored.

Of course, there's no reason to have the property in the first place- any of the properties declared in this snippet. They just exist to create confusion, especially as SetSearch not only sets the property after doing some null checks, but also returns the value. It also checks for an empty string, which is clearly not necessary, as it will return an empty string if the parameter is empty.

I know nothing about the implementation of Repository.Search, but I also have a suspicion that the second parameter allows you to send a pass a filter to select for All entries, ActiveOnly, or InactiveOnly, or something similar. In the Search method we search for All entries, but in the Page_Load event, we use LINQ to filter where r.isActive. I can't prove that they're fetching way more records than they mean to, but we all know they are.

Well, they're not, since this code doesn't even compile, but they wanted to.

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

https://thedailywtf.com/articles/world-class-contracting


Метки:  

CodeSOD: A Date With Yourself

Вторник, 15 Июня 2021 г. 09:30 + в цитатник

Once upon a time, someone wanted to add a banner to a web page. They also wanted the banner to only appear after a certain date. Jack stumbled across their implementation when trying to understand why the banner would vanish for two weeks at the start of every month.

// get date var MyDate = new Date(); var MyDateString; MyDate.setDate(MyDate.getDate()); MyDateString = ('0' + MyDate.getDate()).slice(-2) + '-' + ('0' + (MyDate.getMonth()+1)).slice(-2) + '-' + MyDate.getFullYear(); if (MyDateString > '13-04-2014') { // do stuff... }

So, let's just start with the bad date handling, complete with hacked together string padding. We convert the actual date to a date string, and then compare against the date string instead of the actual date itself. Yes, very bad, very useless, and clearly the source of the bug that got Jack's attention. Since it's string comparisons, '01-05-2021' is "before" '13-04-2014'.

But I had to skip over something important to get there.

MyDate.setDate(MyDate.getDate());

I love that line. It's useless. It has nothing actually to do with what the code is actually trying to do. It's the sort of thing that even a developer who doesn't understand anything would have to read that and wonder why it was there.

But it's there. It isn't going anywhere.

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

https://thedailywtf.com/articles/a-date-with-yourself


Метки:  

CodeSOD: Experience is Integral

Понедельник, 14 Июня 2021 г. 09:30 + в цитатник

Behind every code WTF is a process WTF. For example, Charles W was recently tasked with updating some file-handling code to match changes in the underlying file-format it parses. This is the C code which parses an integer:

if ((*p == '-' || ('0' <= *p && '9' >= *p)) && retCode == -256) { retCode = 0; p = _tcsrev(p); if (*p == ' ') p++; for (i = 0; '0' <= *p && '9' >= *p; i++) { retCode += (int)pow(10, (double)i) * ((int)*p - 0x30); p++; } if (*p == '-') retCode *= -1; }

This code does the basic, CS101 approach to parsing strings into integers, which is to go character by character and multiply by the appropriate power of ten. While no program should ever do this when there are perfectly fine built-ins, like wcstol, this isn't an utter disaster of a code block. Now, this is C and it's doing a bunch of pointer manipulation, it's certainly not safe code. Malformed inputs could almost certainly ruin your day here. It's bad and dangerous code.

But the code isn't the WTF. Note how this is very much the approach a college student or novice programmer might take? Well, fifteen years ago, Charles's employer hired on a college freshman doing a "work study" program. The student was "very good at programming", and so someone told them to implement the file parsing code and then let them go to town. No one checked in beyond "make sure it compiles and runs".

The result is a gigantic blob of code that looks like it was written by a talented but inexperienced college student. Wheels are reinvented. The difficult solution is usually preferred to the simple and clear one. It swings wildly from "overly modularized" to "it's okay if functions are 500 lines long", and "everything is documented" to "I forgot how to put in comments today".

And this is the code that they've been shipping for fifteen years. Charles is among the first to touch it. Which, hey, good on that mystery college student for writing code that was at least reliable enough that nobody had to deal with it before now. Shame on the employer, however, who tried to get important work done on the cheap by hiring inexperienced labor and providing them no supervision.

This is a case where, sure, the code isn't good, but the WTF is how that code got written. Charles adds, "That student is apparently working as a programmer somewhere…", and I hope that along the way they've found employers that could provide them guidance instead of just heaving them into the deep end and getting lucky.

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

https://thedailywtf.com/articles/experience-is-integral


Метки:  

Error'd: Unspoken

Пятница, 11 Июня 2021 г. 09:30 + в цитатник

It's been quite a few years since I was last in Silicon Valley. So it wouldn't surprise me at all if some enterprising restaurateur has unveiled a trendy pub and stolen all the humorous thunder from Sean's submission. I'll be more surprised if they haven't.

Says Sean K. "I love trying new beers, but these varieties remind me too much of work." 418's all around! Alas, the keg of 204 has kicked.

beer

 

Meanwhile, we can't count on Eric K. anymore. "Port 31 of the HP switch is offline, but which one?" he counterfactually queries.

offbyone

 

Preparing for some post-pandemic adventure, peripatetic Matias is raring to explore far from home. "Thanks for offering to take me to the local site that I am currently browsing!" he declares.

race

 

Reader Rob H. shares a slightly Kafkaesque encounter. "Microsoft must have a different definition of optional than I do. One of the 'optional' settings in Edge is turned on, but it's disabled so that I can't turn it off!"

optional

 

But Mike T. tops it with this winner of a Catch-22. "NVidia thinks my old password is so bad I can't even change it."

pass

 

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

https://thedailywtf.com/articles/unspoken


Метки:  

CodeSOD: Quite the Event

Четверг, 10 Июня 2021 г. 09:30 + в цитатник

A few years back, Alvin was in college, and took his first formal summer job as a programmer. It was supposed to be just some HTML layout work, and the designer handed him a few sample pages. "Just do it like this."

The "sample pages" were a mishmash of random indentation, huge swathes of commented out code, and all those other little traits of "someone's just coding in production, aren't they?" that crop up in files. Still, it was just some HTML layout work, so how hard could it be?

Not too hard- until Alvin started popping up the DOM inspector. Every time he opened debugging windows in his browser, the page started misbehaving. Menus stopped staying popped open, or would pop open at seemingly random intervals. He could refresh, and it would go away, but the next time he opened (or closed) the DOM inspector, the problems would come back.

In the one JavaScript file in the project, Alvin found this:

$(document).ready(websitefunction); $(window).resize(websitefunction); function websitefunction(){ $.slidebars(); $('select').each(function(){ back_position = $(this).width()-20; back_position1 = back_position+'px 13px'; $(this).css('background-position',back_position1); }); $('.btn-default').click(function(){ $(this).parent().find('.btn-default').removeClass('active'); $(this).addClass('active'); }); $('.slb_btn1').click(function(){ $('.slb_row1').show(); }); $('.slb_btn2').click(function(){ $('.slb_row1').hide(); $('.slb_row2').show(); }); $('.slb_btn3').click(function(){ $('.slb_row2').hide(); }); $('.slb_btn4').click(function(){ $('.slb_row2').show(); }); if($(document).width()>770){ $('.submenu').width($(document).width()); for(i=1;i<5;i++){ arrow_left = $('.sub_'+i).offset().left+ $('.sub_'+i).width()/2; $('.arrow'+i).css({'left':arrow_left}); } $('.sub_1').mouseover( function(){ $('.submenu').hide(); $('.pro_service').slideDown(100) }); $('.sub_2').mouseover( function(){ $('.submenu').hide(); $('.clien_parner').slideDown(100) }); $('.sub_3').mouseover( function(){ $('.submenu').hide(); $('.help_service').slideDown(100) } ) $('.sub_4').mouseover( function(){ $('.submenu').hide(); $('.my_profile').slideDown(100) } ); $('.submenu').click(function(e){ e.stopPropagation(); }); $(document).click(function(){ $('.submenu').slideUp(100); }); } }

There's a lot to dislike about this wall of event handler registrations, but it's the first two lines that really tell us the story:

$(document).ready(websitefunction); $(window).resize(websitefunction);

When the document is ready, invoke the websitefunction which registers all the event handlers. This is a reasonable and normal thing to do. When the window is resized- we do the same thing, without clearing out any of the existing event handlers. Each time the window gets resized (whether by pulling up debugging tools or by just resizing the browser window) we duplicate the existing event handlers.

If nothing else, Alvin learned some examples of what not to do on that summer job.

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

https://thedailywtf.com/articles/quite-the-event


Метки:  

Поиск сообщений в rss_thedaily_wtf
Страницы: 124 ... 106 105 [104] 103 102 ..
.. 1 Календарь