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

Поиск сообщений в 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: All the Rest Have Thirty One…

Среда, 14 Февраля 2018 г. 14:30 + в цитатник

Aleksei received a bunch of notifications from their CI system, announcing a build failure. This was interesting, because no code had changed recently, so what was triggering the failure?

        private BillingRun CreateTestBillingRun(int billingRunGroupId, DateTime? billingDate, int? statusId)
        {
            return new BillingRun
            {
                BillingRunGroupId = billingRunGroupId,
                PeriodStart = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1),
                BillingDate = billingDate ?? new DateTime(DateTime.Today.Year, DateTime.Today.Month, 15),
                CreatedDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 30),
                ItemsPreparedDate = new DateTime(2017, 4, 7),
                CompletedDate = new DateTime(2017, 4, 8),
                DueDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 13),
                StatusId = statusId ?? BillingRunStatusConsts.Completed,
                ErrorCode = "ERR_CODE",
                Error = "Full error description",
                ModifiedOn = new DateTime(2017, 1, 1)
            };
        }

Take a look at the instantiation of CreatedDate. I imagine the developer’s internal monologue went something like this:

Okay, the Period Start is the beginning of the month, the Billing Date is the middle of the month, and Created Date is the end of the month. Um… okay, well, beginning is easy. That’s the 1st. Phew. Okay, but the middle of the month. That’s hard. Oh, wait, wait a second! It’s billing, so I bet the billing department has a day they always send out the bills. Let me send an email to Steve in billing… oh, look at that. It’s always the 15th. Great. Boy. This programming stuff is easy. Whew. Okay, so now the end of the month. This one’s tricky, because months have different lengths, sometimes 30 days, and sometimes 31. Let me ask Steve again, if they have any specific requirements there… oh, look at that. They don’t really care so long as it’s the last day or two of the month. Great. I’ll just use 30, then. Good thing there aren’t any months with a shorter length.
Y’know, I vaguely remember reading a thing that said tests should always use the same values, so that every run tests exactly the same combination of inputs. I think I saved a bookmark to read it later. Should I read it now? No! I should commit this code, let the CI build run, and then mark the requirement as complete.
Boy, this programming stuff is easy.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/all-the-rest-have-thirty-one


Метки:  

Budget Cuts

Вторник, 13 Февраля 2018 г. 14:30 + в цитатник

Xavier was the head of a 100+ person development team. Like many enterprise teams, they had to support a variety of vendor-specific platforms, each with their own vendor-specific development environment and its own licensing costs. All the licensing costs were budgeted for at year’s end, when Xavier would submit the costs to the CTO. The approval was a mere formality, ensuring his team would have everything they needed for another year.

Unfortunately, that CTO left to pursue another opportunity. Enter Greg, a new CTO who joined the company from the financial sector. Greg was a penny-pincher on a level that would make the novelty coin-smasher you find at zoos and highway rest-stops jealous. Greg started cutting costs left and right immediately. When the time came for budgeting development tool licensing, Greg threw down the gauntlet on Xavier’s “wild” spending.

Alan Rickman, in Galaxy Quest, delivering the line, 'By Grabthar's Hammer, what a savings' while looking like his soul is dying forever. "By Grabthar's Hammer, what a savings."

“Have a seat, X-man,” Greg offered, in a faux-friendly voice. “Let’s get to the point. I looked at your proposal for all of these tools, your team supposedly ‘needs’. $40,000 is absurd! Do you think we print money? If your team were any good,, they should be able to do everything they need without these expensive, gold-plated programs!”

Xavier was taken aback by Greg’s brashness, but he was prepared for a fight. “Greg, these tools are vital to our development efforts. There are maybe a few products we could do without, but most of them are absolutely required. Even the more ‘optional’ ones, like our refactoring and static analysis tools, they save us money and time and improve code quality. Not having them would be more expensive than the license.”

Greg scowled and tented his fingers. “There is no chance I’m approving this as it stands. Go back and figure out what you can do without. If you don’t cut this cost down, I’ll find an easier way to reduce expenses… like by cutting bonuses… or staff.”

Xavier spent the next few days having an extensive tool review with his lead developers. Many of the vendor-specific tools had no alternative, but there were a few third party tools they could do without, or use an open-source equivalent. Across the team of 100+ developers, the net cost savings would be $4,000, or 10%.

Xavier didn’t expect that to make Greg happy, but it was the best they could do. The following morning, Xavier presented his findings in Greg’s office, and it went smoother than expected. “Listen, X. I want this cost down even more, but we’re running out of time to approve this year’s budget. Since I did so much work cutting costs in other ways, I’ll submit this to finance. But enjoy your last year of all these fancy tools! Next year, things will be different!”

Xavier was relieved he didn’t have to fight further. Perhaps, over the next year, he could further demonstrate the necessity of their tooling. With the budget resolved, Xavier had some much-overdue vacation time. He had saved up enough PTO to spend a month in the Australian Outback. Development tools and budgets would be the furthest thing from his mind.

Three great weeks in the land down under were enhanced by being mostly cut off from communications from anyone in the company. During a trip through a town with cell phone reception, Xavier decided to check his voicemail, to make sure the sky wasn’t falling. Dave, his #2 in command, had left an urgent message two days prior.

“Xavier!” Dave shouted on the other end. “You need to get back here soon. Greg never paid the invoices for anything in our stack. We’re sitting here with a huge pile of unlicensed stuff. We’ve been racking up unlicensed usage and support costs, and Greg is going to flip when he sees our monthly statements.” With deep horror, Dave added, “One of the licenses he didn’t pay was for Oracle!”

Xavier reluctantly left the land of dingoes and wallabies to head back home. He arrived just about the same time the first vendor calls demanding payment did. The costs from just three weeks of unlicensed usage of enterprise software was astronomical. Certainly more than just buying the licenses would have been in the first place. Xavier scheduled a meeting with Greg to decide what to do next.

The following Monday, the dreaded meeting was on. “Sit,” Greg said. “I have some good news, and some bad news. The good news is that I’ve found a way to pay these ridiculous charges your team racked up.” Xavier leaned forward in his chair, eager to learn how Greg had pulled it off. “The bad news is that I’ve identified a redundant position- yours.”

Xavier slumped into his chair.

Greg continued. “While you were gone, I realized we were in quite capable hands with Dave, and his salary is quite a bit lower than yours. Coincidentally, the original costs and these ridiculous penalties add up to an amount just a little less than your annual salary. I guess you’re getting your wish: the development team can keep the tools you insist they need to do their jobs. It seems you were right about saving money in the long run, too.”

Xavier left Greg’s office, stunned. On his way out for the last time, he stopped by Dave to congratulate him on the new promotion.

“Oh,” Dave said, sourly, “it’s not a promotion. They’re just eliminating your position. What, you think Greg would give me a raise?”

[Advertisement] Infrastructure as Code built from the start with first-class Windows functionality and an intuitive, visual user interface. Download Otter today!

https://thedailywtf.com/articles/budget-cuts


Метки:  

Coded Smorgasbord: If It's Stupid and It Works

Понедельник, 12 Февраля 2018 г. 14:30 + в цитатник

On a certain level, if code works, it can only be so wrong. For today, we have a series of code blocks that work… mostly. Despite that, each one leaves you scratching your head, wondering how, exactly this happened.


Lisa works at a web dev firm that just picked up a web app from a client. They didn’t have much knowledge about what it was or how it worked beyond, “It uses JQuery?”

Well, they’re technically correct:

if ($(document.getElementById("really_long_id_of_client_side_element")).checked) {
    $(document.getElementById("xxxx1")).css({ "background-color": "#FFFFFF", "color": "Black" });
    $(document.getElementById("xxxx2")).css({ "background-color": "#FFFFFF", "color": "Black" });
    $(document.getElementById("xxxx3")).css({ "background-color": "#FFFFFF", "color": "Black" });
    $(document.getElementById("xxxx4")).css({ "background-color": "#FFFFFF", "color": "Black" });
};

In this case, they’re ignoring the main reason people use jQuery- the ability to easily and clearly fetch DOM elements with CSS selectors. But they do use the css function as intended, giving them an object-oriented way to control styles. Then again, one probably shouldn’t set style properties directly from JS anyway, that’s what CSS classes are for. Then again, why mix #FFFFFF and Black, when you could use white or #000000

Regardless, it does in fact use JQuery.


Dave A was recently trying to debug a test in Ruby, and found this unique construct:

if status == status = 1 || status = 2 || status = 3
  @msg.stubs(:is_reply?).returns true
else
  @msg.stubs(:is_reply?).returns false
end

This is an interesting case of syntactically correct nonsense that looks incorrect. status = 1 returns a 1, a “truthy” value, thus short circuiting the || operator. In this code, if status is undefined, it returns true and sets status equal to 1. The rest of the time it returns false and sets status equal to 1.

What the developer meant to do was check if status was 1, 2 or 3, e.g. if status == 1 || status == 2…, or, to use a more Ruby idiom: if [1, 2, 3].include? status. Still, given the setup for the test, the code actually worked until Dave changed the pre-conditions.


Meanwhile, Leonardo Scur came across this JavaScript reinvention of an array:

tags = {
  "tags": {
    "0": {"id": "asdf"},
    "1": {"id": "1234"},
    "2": {"id": "etc"}
  },
  "tagsCounter": 3,
  // … below this are reimplementations of common array methods built to work on `tags`
}

This was part of a trendy front-end framework he was using, and it’s obvious that arrays indexed by integers are simply too mainstream. Strings are where it’s at.

This library is in wide use, meant to add simple tagging widgets to an AngularJS application. It also demonstrates a strange way to reinvent the array.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/if-it-s-stupid-and-it-works


Метки:  

Error'd: Whatever Happened to January 2nd?

Пятница, 09 Февраля 2018 г. 14:30 + в цитатник

"Skype for Business is trying to tell me something...but I'm not sure exactly what," writes Jeremy W.

 

"I was looking for a tactile switch. And yes, I absolutely do want an operating switch," writes Michael B.

 

Chris D. wrote, "While booking a hair appointment online, I found that the calendar on the website was a little confused as to how calendars work."

 

"Don't be fooled by the image on the left," wrote Dan D., "If you get caught in the line of fire, you will assuredly get soaked!"

 

Jonathan G. writes, "My local bar's Facebook ad shows that, depending on how the viewer frames it, even an error message can look appealing."

 

"I'll have to check my calendar - I may or may not have plans on the Nanth," wrote Brian.

 

[Advertisement] Easily create complex server configurations and orchestrations using both the intuitive, drag-and-drop editor and the text/script editor.  Find out more and download today!

https://thedailywtf.com/articles/whatever-happened-to-january-2nd


Метки:  

CodeSOD: I Take Exception

Четверг, 08 Февраля 2018 г. 14:30 + в цитатник

We've all seen code that ignores errors. We've all seen code that simply rethrows an exception. We've all seen code that wraps one exception for another. The submitter, Mr. O, took exception to this exceptionally exceptional exception handling code.

I was particularly amused by the OutOfMemoryException handler that allocates another exception object, and if it fails, another layer of exception trapping catches that and attempts to allocate yet another exception object. if that fails, it doesn't even try. So that makes this an exceptionally unexceptional exception handler?! (ouch, my head hurts)

It contains a modest amount of fairly straightforward code to read config files and write assorted XML documents. And it handles exceptions in all of the above ways.

You might note that the exception handling code was unformatted, unaligned and substantially larger than the code it is attempting to protect. To help you out, I've stripped out the fairly straightforward code being protected, and formatted the exception handling code to make it easier to see this exceptional piece of code (you may need to go full-screen to get the full impact).

After all, it's not like exceptions can contain explanatory text, or stack context information...

namespace HotfolderMerger {
  public class Merger : IDisposable {
    public Merger() {
      try {
          object section = ConfigurationManager.GetSection("HFMSettings/DataSettings");
          if (section == null) throw new MergerSetupException();
          _settings = (DataSettings)section;
      } catch (MergerSetupException) {
        throw;
      } catch (ConfigurationErrorsException ex){
        throw new MergerSetupException("Error in configuration", ex);
      } catch (Exception ex) {
        throw new MergerSetupException("Unexpected error while loading configuration",ex);
      }
    }

    // A whole bunch of regex about as complex as this one...
    private readonly Regex _fileNameRegex = new Regex(@"^(?[A-Za-z0-9]{1,10})_(?[A-Za-z0-9]{1,})_(?\d{1,})_(?\d{1,})(_(?\d+))?\.(?\w{0,3})$");

    public void MergeFiles() {
      try {
          foreach (FileElement filElement in _settings.Filelist) {
            // Lots of declarations here...
            foreach (FileInfo fi in hotfolder.GetFiles()) {
              try {
                  // 35 lines of innocuous code..
              } catch (ArgumentException ex) {
                throw new BasisException(ex, int.Parse(ErrorCodes.MergePreRunArgumentException),     ErrorMessages.MergePreRunArgumentException);
              } catch (ConfigurationException ex) {
                throw new BasisException(ex, int.Parse(ErrorCodes.MergePreRunConfigurationException),ErrorMessages.MergePreRunConfigurationException);
              } catch (Exception ex) {
                throw new UnexpectedMergerException("Unexpected exception while setting up for merge!", ex);
              }
            
              try {
                  // 23 lines of StreamReader code to load some XML from a file...
              } catch (OutOfMemoryException ex) {
                // OP: so if we're out of memory, how is this new exception going to be allocated? 
                //     Maybe in the wrapping "try/catch Exception" - which allocates a new UnexpectedMergerException object??? Oh, wait...
                throw new BasisException(  ex,int.Parse(ErrorCodes.MergeRunOutOfMemoryException),   ErrorMessages.MergeRunOutOfMemoryException);
              } catch (ConfigurationException ex) {
                throw new BasisException(  ex, int.Parse(ErrorCodes.MergeRunConfigurationException),ErrorMessages.MergeRunConfigurationException);
              } catch (FormatException ex) {
                throw new BasisException(  ex, int.Parse(ErrorCodes.MergeRunFormatException),       ErrorMessages.MergeRunFormatException);
              } catch (ArgumentException ex) { 
                throw new BasisException(    ex, int.Parse(ErrorCodes.MergeRunArgumentException),   ErrorMessages.MergeRunArgumentException);
              } catch (SecurityException ex) {
                throw new BasisException(  ex, int.Parse(ErrorCodes.MergeRunSecurityException),     ErrorMessages.MergeRunSecurityException);
              } catch (IOException ex) {
                throw new BasisException(  ex, int.Parse(ErrorCodes.MergeRunIOException),           ErrorMessages.MergeRunIOException);
              } catch (NotSupportedException ex) {
                throw new BasisException(  ex, int.Parse(ErrorCodes.MergeRunNotSupportedException), ErrorMessages.MergeRunNotSupportedException);
              } catch (Exception ex) {
                throw new UnexpectedMergerException("Unexpected exception while merging!", ex);
              }
            }
            // ...
          }
      } catch (UnexpectedMergerException) {
        throw;
      } catch (BasisException ex) {
        BasisLog.WriteError(ex);
      } catch (Exception ex) {
        throw new UnexpectedMergerException("Unexpected error while attempting to parse settings prior to merge", ex);
      }
    }

    private static void prepareNewMergeFile(ref XmlTextWriter xtw, string filename, int numfiles) {
      if (string.IsNullOrEmpty(filename))
         throw new BasisException(    int.Parse(ErrorCodes.MergeSetupNullReferenceException),       ErrorMessages.MergeSetupNullReferenceException, "filename parameter was null or empty");
      try {
          // Use XmlTextWriter to concatenate ~30 lines of canned XML...
      } catch (InvalidOperationException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeSetupInvalidOperationException),     ErrorMessages.MergeSetupInvalidOperationException);
      } catch (ArgumentException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeSetupArgumentException),             ErrorMessages.MergeSetupArgumentException);
      } catch (IOException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeSetupIOException),                   ErrorMessages.MergeSetupIOException);
      } catch (UnauthorizedAccessException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeSetupUnauthorizedAccessException),   ErrorMessages.MergeSetupUnauthorizedAccessException);
      } catch (SecurityException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeSetupSecurityException),             ErrorMessages.MergeSetupSecurityException);
      } catch (Exception ex) {
        throw new UnexpectedMergerException("Unexpected exception while setting up for merge!", ex);
      }
    }

    private void closeMergeFile(ref XmlTextWriter xtw, ref List<FileInfo> filesComplete, string filename, double i) {
      if (xtw == null)
         throw new BasisException(int.Parse(ErrorCodes.MergeCleanupNullReferenceException),          ErrorMessages.MergeCleanupNullReferenceException, "xtw ref parameter was null");
      if (filesComplete == null)
         throw new BasisException(int.Parse(ErrorCodes.MergeCleanupNullReferenceException),          ErrorMessages.MergeSetupNullReferenceException,   "filesComplete ref parameter was null");
      if (string.IsNullOrEmpty(filename))
         throw new BasisException(int.Parse(ErrorCodes.MergeCleanupNullReferenceException),          ErrorMessages.MergeSetupNullReferenceException,   "filename parameter was null or empty");

      try {
          // ~ 30 lines of XmlTextWriter, StreamWriter and File IO...
      } catch (ArgumentException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeCleanupArgumentException),           ErrorMessages.MergeCleanupArgumentException);
      } catch (InvalidOperationException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeCleanupInvalidOperationException),   ErrorMessages.MergeCleanupInvalidOperationException);
      } catch (UnauthorizedAccessException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeCleanupUnauthorizedAccessException), ErrorMessages.MergeCleanupUnauthorizedAccessException);
      } catch (IOException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeCleanupIOException),                 ErrorMessages.MergeCleanupIOException);
      } catch (NullReferenceException ex) {
        throw new BasisException(int.Parse(ErrorCodes.MergeCleanupNullReferenceException),          ErrorMessages.MergeCleanupNullReferenceException, "unknown exception details");
      } catch (NotSupportedException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeCleanupNotSupportedException),       ErrorMessages.MergeCleanupNotSupportedException);
      } catch (MergerException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeCleanupMergerException),             ErrorMessages.MergeCleanupMergerException);
      } catch (SecurityException ex) {
        throw new BasisException(ex, int.Parse(ErrorCodes.MergeCleanupSecurityException),           ErrorMessages.MergeCleanupSecurityException);
      } catch (Exception ex) {
        throw new UnexpectedMergerException("Unexpected exception while merging!", ex);
      }
    }
  }
}
[Advertisement] Otter, ProGet, BuildMaster – robust, powerful, scalable, and reliable additions to your existing DevOps toolchain.

https://thedailywtf.com/articles/i-take-exception


Метки:  

CodeSOD: How To Creat Socket?

Среда, 07 Февраля 2018 г. 14:30 + в цитатник

JR earned a bit of a reputation as the developer who could solve anything. Like most reputations, this was worse than it sounded, and it meant he got the weird heisenbugs. The weirdest and the worst heisenbugs came from Gerry, a developer who had worked for the company for many, many years, and left behind many, many landmines.

Once upon a time, in those Bad Old Days, Gerry wrote a C++ socket-server. In those days, the socket-server would crash any time there was an issue with network connectivity. Crashing services were bad, so Gerry “fixed” it. Whatever Gerry did fell into the category of “good enough”, but it had one problem: after any sort of network hiccup, the server wouldn’t crash, but it would take a very long time to start servicing requests again. Long enough that other processes would sometime fail. It was infrequent enough that the bug had stuck around for years, but finally, someone wanted Something Done™.

JR got Something Done™, and he did it by looking at the CreatSocket method, buried deep in a "God" class of 15,000 lines.

void UglyClassThatDidEverything::CreatSocket() {
    while (true) {
                try {
                        m_pSocket = new Socket((ip + ":55043").c_str());
                        if (m_pSocket != null) {
                                // LOG.info("Creat socket");
                                m_pSocket->connect();
                                break;
                        } else {
                                // LOG.info("Creat socket failed");
                                // usleep(1000);
                                // sleep(1);
                                sleep(5);
                        }
                } catch (...) {
                    if (m_pSocket == null) {
                                // LOG.info("Creat socket failed");
                                sleep(5);
                                CreatSocket();
                                sleep(5);
                        }
                }
        }
}

The try portion of the code provides an… interesting take on handling socket creation. Create a socket, and grab a handle. If you don’t get a socket for some reason, sleep for 5 seconds, and then the infinite while loop means that it’ll try again. Eventually, this will hopefully get a socket. It might take until the heat death of the universe, or at least until the half-created-but-never-cleaned-up sockets consume all the filehandles on the OS, but eventually.

Unless of course, there’s an exception thrown. In that case, we drop down into the catch, where we sleep for 5 seconds, and then call CreatSocket recursively. If that succeeds, we still have that extra call to sleep which guarantees a little nap, presumably to congratulate ourselves for finally creating a socket.

JR had a simple fix for this code: burn it to the ground and replace it with a more normal approach to creating sockets. Unfortunately, management was a bit gun-shy about making any major changes to Gerry’s work. That recursive call might be more important than anyone imagined.

JR had a simpler, if stupider fix: remove the final call to sleep(5) after creating the socket in the exception handler. It wouldn’t make this code any less terrible, but it would mean that it wouldn’t spend all that time waiting to proceed even after it had created a socket, thus solving the initial problem: that it takes a long time to recover after failure.

Unfortunately, management balked at removing a line of code. “It wouldn’t be there if it weren’t important. Instead of removing it, can you just comment it out?”

JR commented it out, closed VIM, and hoped never to touch this service again.

[Advertisement] Easily create complex server configurations and orchestrations using both the intuitive, drag-and-drop editor and the text/script editor.  Find out more and download today!

https://thedailywtf.com/articles/how-to-creat-socket


Метки:  

For Want of a CR…

Вторник, 06 Февраля 2018 г. 14:30 + в цитатник

A few years ago I was hired as an architect to help design some massive changes to a melange of existing systems so a northern foreign bank could meet some new regulatory requirements. As a development team, they gave me one junior developer with almost a year of experience. There were very few requirements and most of it would be guesswork to fill in the blanks. OK, typical Wall Street BS.

Horseshoe nails, because 'for want of a nail, the shoe was lost…

The junior developer was, well, junior, but bright, and he remembered what you taught him, so there was a chance we could succeed.

The setup was that what little requirements there were would come from the Almighty Project Architect down to me and a few of my peers. We would design our respective pieces in as generic a way as possible, and then oversee and help with the coding.

One day, my boss+1 has my boss have the junior guy develop a web service; something the guy had never done before. Since I was busy, it was deemed unnecessary to tell me about it. The guy Googled a bit and put something together. However, he was unsure of how the response was sent back to the browser (e.g.: what sort of line endings to use) and admitted he had questions. Our boss said not to worry about it and had him install it on the dev server so boss+1 could demo it to users.

Demo time came, and the resulting output lines needed an extra newline between them to make the output look nice.

The boss+1 was incensed and started telling the users and other teams that our work was crap, inferior and not to be trusted.

WTF?!

When this got back to me, I went to have a chat with him about a) going behind my back and leaving me entirely out of the loop, b) having a junior developer do something in an unfamiliar technology and then deploying it without having someone more experienced even look at it, c) running his mouth with unjustified caustic comments ... to the world.

He was not amused and informed us that the work should be perfect every time! I pointed out that while everyone strives for just that, that it was an unreasonable response, and doesn't do much to foster team morale or cooperation.

This went back and forth for a while until I decided that this idiot simply wasn't worth my time.

A few days later, I hear one of my peers having the same conversation with our boss+1. A few days later, someone else. Each time, the architect had been bypassed and some junior developer missed something; it was always some ridiculous trivial facet of the implementation.

I got together with my peers and discussed possibly instituting mandatory testing - by US - to prevent them from bypassing us to get junior developers to do stuff and then having it thrown into a user-visible environment. We agreed, and were promptly overruled by boss+1. Apparently, all programmers, even juniors, were expected to produce perfect code (even without requirements) every time, without exception, and anyone who couldn't cut it should be exposed as incompetent.

We just shot each other the expected Are you f'g kidding me? looks.

After a few weeks of this, we had all had enough of the abuse and went to boss+2, who was totally disinterested.

We all found other jobs, and made sure to bring the better junior devs with us.

[Advertisement] Easily create complex server configurations and orchestrations using both the intuitive, drag-and-drop editor and the text/script editor.  Find out more and download today!

https://thedailywtf.com/articles/for-want-of-a-cr


Метки:  

CodeSOD: PRINCESS DEATH CLOWNS

Понедельник, 05 Февраля 2018 г. 14:30 + в цитатник

Adam recently tried to claim a rebate for a purchase. Rebate websites, of course, are awful. The vendor doesn’t really want you to claim the rebate, after all, so even if they don’t actively try and make it user hostile, they’re also not going to go out of their way to make the experience pleasant.

In Adam’s case, it just didn’t work. It attempted to use a custom-built auto-complete textbox, which errored out and in some cases popped up an alert which read: [object Object]. Determined to get his $9.99 rebate, Adam did what any of us would do: he started trying to debug the page.

The HTML, of course, was a layout built from nested tables, complete with 1px transparent GIFs for spacing. But there were a few bits of JavaScript code which caught Adam’s eye.

function doTheme(myclass) {
         if ( document.getElementById ) {
                if(document.getElementById("divLog").className=="princess") {
                        document.getElementById("divLog").className="death"
                } else {
                        if(document.getElementById("divLog").className=="death") {
                                document.getElementById("divLog").className="clowns"
                        } else {
                                if(document.getElementById("divLog").className=="clowns") {
                                        document.getElementById("divLog").className="princess"
                                }
                        }
                }
                document.frmLog.myClass.value=document.getElementById("divLog").className;
        } else if ( document.all ) {
                if(document.all["divLog"].className=="princess") {
                        document.all["divLog"].className="death"
                } else {
                        if(document.all["divLog"].className=="death") {
                                document.all["divLog"].className="clowns"
                        } else {
                                if(document.all["divLog"].className=="clowns") {
                                        document.all["divLog"].className="princess"
                                }
                        }
                }
                document.frmLog.myClass.value=document.all["divLog"].className;
        }
}

This implements some sort of state machine. If the state is “princess”, become “death”. If the state is “death”, become “clowns”. If the state is “clowns”, go back to being a “princess”. Death before clowns is a pretty safe rule.

This code also will work gracefully if document.getElementById is unavailable, meaning it works all the way back to IE4. That’s backwards compatibility. Since it doesn't work in Adam's browser, it missed out on the forward compatibility, but it's got backwards compatibility.

To round out the meal, Adam also provides a little bit of dessert for this entry of awful code.

//DEBRA, THIS DOES THE IMAGE MOUSEOVER THING.  
//ALL YOU HAVE TO DO IS TELL IT WHICH OBJECT YOU ARE REFERRING TO, AND WHAT YOU WANT TO  
//CHANGE THE IMAGE SOURCE TO.

function over(myimage,str) {  
        document[myimage].src=eval(str).src  
}

DEBRA I HOPE YOU GOT A JOB WHERE YOU DON’T HAVE TO WORK WITH THIS AWFUL WEBSITE ANYMORE.

Adam used some google-fu and found an alternate site that allowed him to redeem his rebate.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/princess-death-clowns


Метки:  

Error'd: The Biggest Loser

Пятница, 02 Февраля 2018 г. 14:30 + в цитатник

"I don't know what's more surprising - losing $2,000,000 or that Yahoo! thought I had $2,000,000 to lose," writes Bruce W.

 

"Autodesk sent out an email about my account's password being changed recently. Now it's up to me to guess which $productName it is!" wrote Tom G.

 

Kurt C. writes, "I kept repeating my mantra: 'Must not click forbidden radio buttons...'"

 

"My son boarded a bus in Toronto and got a free ride when the driver showed him this crash message," Ari S. writes.

 

"For those who are in denial about global warming, may I please direct you to conditions in Wisconsin," wrote Chelsie S.

 

Billie J. wrote, "Sorry there, Walmart, but that's not how math works."

 

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/the-biggest-loser


Метки:  

We Sell Bonds!

Четверг, 01 Февраля 2018 г. 14:30 + в цитатник

We Sell Bonds!

The quaint, brick-faced downtown office building was exactly the sort of place Alexis wanted her first real programming job to be. She took a moment to just soak in the big picture. The building's facade oozed history, and culture. The busy downtown crowd flowed around her like a tranquil stream. And this was where she landed right out of college-- if this interview went well.

Alexis went inside, got a really groovy start-up vibe from the place. The lobby slash waiting room slash employee lounge slash kitchen slash receptionist desk was jam packed full of boxes of paperwork waiting to be unpacked and filed (once a filing cabinet was bought). The walls, still the color of unpainted drywall, accented with spats of plaster and glue-tape. Everything was permeated with chaotic beginnings and untapped potential.

Her interviewer, Mr. Chen, the CEO of the company, lead her into the main conference room, which she suspected was the main conference room by virtue of being the only conference room. The faux-wood table, though moderately sized, still barely left room for herself and the five interviewers, crammed into a mish-mash of conference-room chairs, office chairs and one barstool. At least this room's walls had seen a coat of paint-- if only a single coat. Framed artwork sat on the ground, leaned up gently against the wall. She shared the artwork's anticipation-- waiting for the last coat of paint and touch-ups to dry, to hang proudly for all to see, fulfilling their destiny as the company grew and evolved around them.

"Thank you for coming in," said Mr. Chen as he sat at the head of the conference table.

"Thank you for having me," Alexis replied, sitting opposite him, flanked by the five other interviewers. She was glad she'd decided to play cautious and wear her formal 'Interview Suit'. She fit right in with the suits and ties everyone else was wearing. "I really dig the office space. How long have you been here?"

"Five years," Mr. Chen answered.

Her contextual awareness barely had time to register the whiplash of unpainted walls and unhung pictures in a long occupied office-- not that she had time to process that thought anyways.

"Let the interview begin now," Mr. Chen said abruptly. "Tell me your qualifications."

"I-- uh, okay," Alexis sat up straight and opened her leather folder, "Does everyone have a copy of my resume? I printed extra in case-- "

"We are a green company," Mr. Chen stated.

Alexis froze for a moment, her hand inches from the stack of resumes. She folded her hands over her own copy, smiled, and recovered. "Okay. My qualifications..." She filled them in on the usual details-- college education, GPA, co-op jobs, known languages and frameworks, contributions to open source projects. It was as natural as any practice interview she'd ever had. Smile. Talk clearly. Make eye contact with each member of the interview team for an appropriate length of time before looking at the next person.

Though doing so made her acutely aware that she had no idea who the other people were. They'd never been introduced. They were just-- there.

As soon as she'd finished her last qualification point, Mr. Chen spoke. "Are you familiar with the bonds market?"

She'd done some cursory Wikipedia research before her interview, but admitted, "An introductory familiarity."

"You are not expected to know it," Mr. Chen said, "The bond market is complicated. Very complicated. Even experienced brokers who know about futures contracts, forward contractions, options, swaps and warrants often have no idea how bonds work. But their customers still want to buy a bond. The brokers are our customers, and allowing them to buy bonds is the sole purpose of 'We Sell Bonds!'."

Though Mr. Chen had a distinctly dry and matter-of-fact way of speaking, she could viscerally HEAR the exclamation point in the company's name.

"Very interesting," Alexis said. Always be sure to compliment the interviewer at some point. "What sort of programming projects would I be working on?"

"The system is very complicated," Mr. Chen retorted. "Benny is our programmer."

One of the suited individuals to her left nodded, and she smiled back at him. At least now she knew one other person's name.

"He will train you before you may modify the system. It is very important the system be working properly, and any development must be done carefully. At least six months of training. But the system gathers lots of data, from markets, and from our customers. That data must be imported into the system. That will be part of your duties."

Again, Alexis found herself sitting behind a default smile while her brain processed. The ad she'd answered had clearly been for a junior developer. It had asked for developer skills, listed must-know programming languages, and even been titled 'Junior Developer'. Without breaking the smile, she asked, "What would you say the ratio of data handling to programming would be?"

"I would say close to one hundred percent."

Alexis' heart sank, and she curled her toes to keep any physical sign of her disappointment showing. She mentally looked to her sliver-linings view. Sure, it was data entry-- but she'd still be hands-on with a complicated financial system. She'd get training. Six months of training, which would be a breeze compared to full-time college. And if there really was that much data entry, then the job would be perfect for a fresh mind. There'd be TONS of room for introducing automation and efficiency. What more could a junior developer want?

"That sounds great," Alexis said, enthusiastic as ever.

"Good," Mr. Chen said. "The job starts on Monday."

Her whiplash systems had already long gone offline from overload. Was that a job offer?

"That-- sounds great!" Alexis repeated.

"Good. Nadine will email your paperwork. Email it back promptly."

And now Alexis knew a second person's name. "I look forward to meeting the whole company," she said aloud.

"You have," Mr. Chen replied, gesturing to the others at the table. "We will return to work now. Good day."

Alexis found herself back on the sidewalk outside the quaint brick-faced downtown office building, gainfully employed and not sure if she actually understood what the heck had just happened. But that was a problem for Monday.

#

Alexis arrived fifteen minutes early for her first day at the quaint brick-faced downtown office-- no, make that HER quaint brick-faced downtown office.

Fourteen minutes later, Mr. Chen unlocked the front-door from the inside, and let her in.

"You're early," he stated, locking the door behind her.

"The early bird gets the worm," she clich'ed.

"You don't need to be early if you are punctual. Follow."

Mr. Chen lead her through the lobby, and once again into the main boardroom. As before, five people sat around the conference table. Alexis figured there'd be formalities and paperwork to file before she got a desk. HER desk! The whole company (all six of them-- though now it was seven) were here to greet her. And, for some reason, they'd brought their laptops.

"You will sit beside Benny," Mr. Chen said, taking his seat.

"I-- huh?"

Next to Benny, there was an empty chair, and an unoccupied laptop. Alexis slunk around the other chairs, careful not to knock over the framed posters that were still propped against the wall, and sat beside the lead programmer.

"Morning meeting before getting down to work, huh?" she said, smiling at him.

Benny gave her a sideways glance. "We are working."

Alexis wasn't sure what he meant-- and then she noticed, for the first time, that everyone was heads down, looking at their screens, typing away. This wasn't just a boardroom. This was her desk. This was everyone's desk.

Over the morning, Benny gave her his split attention-- interspersing his work with muttering instructions to her; how to log in, where the data files were, how to install Excel. He would only talk to her in-between steps of his task; never interrupting a step to give her attention. Sometimes she just sat there and watched him watch a progress bar. She gathered he was upgrading a server's instance of SQL Server from version "way too old" to version "still way too old, but not as much".

After lunch (also eaten at the shared desk), Benny actually looked at her.

"Time for your first task," he said, giving her a sheet of paper. "We have a new financial institution buying bonds from us. They will use our Single SignOn Solution. You will need to create these accounts."

She took the sheet of paper, a simple printed table with first name, last name, company name, username and password.

Alexis was recently enough out of college that "Advanced Security Practices 401" was still fresh in her mind-- and seeing a plaintext password made her bones nearly crawl out of her skin.

"I-- um-- are there supposed to be passwords here?"

Benny nodded. "Yes. To facilitate single sign-on, usernames and passwords in 'We Sell Bonds!' website must exactly match those used in the broker's own system. Their company signs up for 'We Sell Bonds!', and they are provided with a website skinned to look like their own. The company's employees are given a seamless experience. Most don't even know they are on a different site."

Her skin gnawed on her bones to keep them in place. "But, if the passwords here are in plaintext, that is their real, actual password?"

Benny gave her the same nod. "They must be. Otherwise we could not log in to test their account."

That either made perfect sense, or had dumbfounded all the sense out of Alexis, so she just said "Ok." The rest of the day was spent creating accounts through an ASP interface, then logging into the site to test them.

When she arrived at the quaint brick-faced office building the next day, there was a large stack of papers at her spot at the communal desk. Benny said, "Mr. Chen was happy with your data entry yesterday."

Mr. Chen, who was seated at the head of the shared desk, didn't look up from his laptop screen. "You are allowed to enter this data too."

"Thank you?" Alexis settled in, and got to work. For every record she entered, a different way of optimizing this system would flitter through her mind. A better entry form, maybe auto-focus the first field? How about an XML dump on a USB disk? Or a SOAP service that could interface directly with the database? There could be a whole validation layer to check the data and pre-emptively catch data errors.

Data errors like the one she was looking at right now. She waited patiently for Benny to complete whatever step of his task he was on, and showed him the offending records.

"I don't see the problem," Benny said, shortly.

"John Smith and Jon Smith both have the same username, jsmith" she said, not sure how to make it more clear.

"Yes, they do," Benny confirmed.

"They can't both have the same username."

"They can!" Mr. Chen's sudden interjection startled her-- though she wasn't sure if it was because of the sharpness of his tone, or because she hadn't actually heard him speak for a day and a half. "Do you not see that they have different passwords?"

"Uh," Alexis checked, "They do. But the username is still the same."

There was no response. Mr. Chen was already looking back at his screen. Benny was looking at her expectantly.

"So users are differentiated by their-- password?" she said, trying to grasp what the implications of that would be. "What if someone changes their password to be-- "

"Users don't change passwords," Benny replied. "That would break single sign-on. If a user changes their password in their home system, their company will submit a change request to us to modify the password on 'We Sell Bonds!'."

Alexis blinked-- this time certain that this made no sense, and she was actually dumbfounded. But Benny must have taken her silence as 'question answered', and immediately started his next task. It made no sense, but she was still a junior developer, fresh out of school; full of ideas but short on experience. Maybe-- yeah, maybe there was a reason to do it this one. One that made sense once she learned to stop thinking so academically. That must be it.

She dutifully entered two records for jsmith and kept working on the pile.

#

Friday. The end of her first real work week. Such a long, long week of data entry, interspersed by being allowed to witness a small piece of the system as Benny worked on his upgrades. At least she knew now which version of SQL Server was in use; and that Benny avoided the braces-verses-no-braces argument by just using vbscript which was "pure and brace-free"; and that stored procedures were allowed because raw SQL was too advanced to trust to human hands.

Alexis stood in front of the quaint brick-faced office building. It was familiar enough now, after even just a week, that she could see the discoloured mortar, and cracked bricks near the foundation, and the smatterings of dirt and debris that came with being on a busy downtown street.

She went into the office, and sat down at the desk. Another stack of papers for her to enter, just like the day before, just like every day this week. Though something was different. In the middle of the table, there was a box of donuts from the local bakery.

"Well, that's nice," she said as she sat down. "Happy Friday?"

Everyone looked up at her at the same time.

"No," Mr. Chen stated, "Friday is not a celebration; please do not detract from Benny's success."

She felt like she wanted to apologize, but she didn't know why. "What's the occasion, Benny?"

"He has completed the upgrade of the database. We celebrate his success."

That seemed reasonable enough. Mr. Chen opened the box. There was an assortment of donuts. Seven donuts. Exactly seven donuts. Not a dozen. Not half a dozen. Seven. Who buys seven donuts?

Mr. Chen selected one, and then the box was passed around. Alexis didn't know much about her coworkers (a fact that, upon thinking about it, was not normal)-- but she did know enough about their positions to recognize the box being passed around in order of seniority. She took the last one, a plain cake donut.

Of course.

"Well," she said, making a silver lining out of a plain donut, "Congratulations, Benny. Cheers to you."

"Thank you," he said, "I was finally able to successfully update the server for the first time last night."

"Nice. When do we roll it out to the live website?"

Benny looked at her a blankly. "The website is live."

"Yeah, I know," Alexis said, swallowing the last bit of donut. It landed hard on the weird feeling she had in her stomach. "But, y'know-- you upgraded whatever environment you were experimenting on, right? So now that that's done, are you, like-- going to upgrade the live, production server over the weekend or something-- like, off hours?"

"I have upgraded the live, production server. That is our server. That is where we do all the work."

Alexis became acutely aware that the weird feeling in her stomach was a perfectly normal and natural reaction to thinking about doing work directly on a live, production server that served hundreds of customers handling millions of dollars.

"Oh."

Mr. Chen finished his donut and said, "Benny is a proper, careful worker. There is no need to waste resources on many environments when one can just do the job correctly in the first place. Again, good work, Benny, and now the day begins."

Everyone turned to their laptops, and so did Alexis, reflectively. She started in on the first stack of papers to enter into the database-- the live, production database she was interfacing directly with-- when she heard a sound she'd never heard before.

A phone rang.

The man beside Mr. Chen-- Trevor, she thought his name was, stood up and excused himself to the lobby to answer the phone. He returned after a few moments, and put a piece of paper on top of her pile.

"That request should be queued at the bottom of her pile," Mr. Chen said as soon as Trevor's hand was off the paper.

"I believe this may be a case of priority," Trevor replied. He had a nice voice. Why hadn't she heard her co-worker's voice after a week of working here? "A user cannot log in."

She glanced down at the paper. There was a username and password jotted down. When she looked back up at Mr. Chen, he waved her to proceed. Alexis pulled up "We Sell Bonds!" home page, and tried to log in as "a.sanders"

The logged-in page popped up. "Huh, seems to be working now."

"No," Trevor said, "You should be logged in as Andrew Sanders from Initech Bonds and Holdings, not Andrew Sanders from Fiduciary Interests."

"But I am logged in as a.sanders from Initiech, see?" she brought up the account details to show Trevor.

"No, I tried it myself. I will show you." Trevor took her laptop, repeated the login steps. "There."

"Huh." Alexis stared at the account information for Andrew Sanders from Fiduciary Interests. "Maybe one of us is typing in the wrong password?"

Alexis tried again, and Trevor tried-- and this time got the results reversed. They tried a new browser session, and both got Initech. Then try tried different browsers and Trevor got Initech twice in a row. They copy and pasted usernames and passwords to and from Notepad. No matter what they tried, they couldn't consistently reproduce which Andrew Sanders they got.

As Alexis tried over and over to come up with something or anything to explain it, Benny was frantically running through code, adding Response.Write("") anywhere he could think might help.

By this point the whole company was watching them. While that shouldn't be noteworthy since the entire company was in the same room, being paid attention to by this particular group of coworkers was extremely noticeable.

And of all the looks that fell on her, the most disconcerting was Mr. Chen's gaze.

"Determine the cause of this disruption to our website," he said flatly.

"I don't get it," Alexis said, "This doesn't make any sense. We should be able to determine what's causing this bug, but-- um-- hang on."

Determine-- the word tugged at her, begging to be noticed. Or begging her to notice something. Something she'd seen on Benny's screen. A SQL query. It reminded her of a term from one of her Database Management exams. Deterministic. Yes, of course!

"Benny, go back to that query you had on screen!" she exclaimed! "Yes, that one!"

As she pointed at Benny's screen, Mr. Chen was already on his feet, heading over. A perfect chance for her to finally prove her worth as a developer.

"That query, right there, for getting the user record. It's using a view and-- may I?" she took over Benny's laptop, focused on the SQL Management Studio, but excitedly talking aloud as she went.

"Programmability... views... VIEW_ALL_USERS... aha! Check it out."

SELECT TOP 100 PERCENT *
FROM TABLE_USERS
ORDER BY UserCreatedDate

"Which," she clicked back to the query, "Is used here..."

SELECT *
FROM TABLE_USERS
WHERE username=@Username and password=@Password

"... and we only use the first record we return, but I've read about this! Okay, like, the select without an ORDER BY returns in random order-- no no no, NON-DETERMINISTIC order, basically however the optimizer felt like returning them, based on which ones returned faster, or what it had for breakfast that day, but totally non-deterministic. No "ORDER BY" means no order. Or at least it is supposed to, but, like, SQL Server 2000 had this bug in the optimizer, which became this epic 'undocumented feature'. When you did TOP 100 PERCENT along with an ORDER BY in a view, the optimizer just bugged the fudge out and did the sorting wrong, but did the sorting wrong in a deterministic way. In effect, it would obey the ORDER BY inside the view, but only by accident. But, like I said, that was a bug in SQL Server 2000, and Benny, WE JUST UPGRADED TO SQL SERVER 2005!"

She held her hands out, the solution at last. Mr. Chen was standing right there. Okay, perfect-- because what had Logical Thinking and Troubleshooting 302 taught her? Don't just identify a PROBLEM, also present a SOLUTION!

"Okay, look-- I bet if I query for users with this username and this password-- " she typed the query in frantically-- "see, right there, that's Andrew Sanders from Initech AND Andrew Sanders from Fiduciary Interests. They both have the same username and password, so they're both returned. I bet no one ever noticed before. That other guy has no activity on his account. So all we really have to do is put the same ORDER BY into the query itself-- and-- click click, copy paste-- there! Log in and-- there's Mr. Initech. Log out, log in, log out, log in-- I could do this all day and we'll get the same results. Tah-dah!"

She sat back in her chair, grinning at her captive audience. But they weren't grinning back. Instead they were averting their gaze. Everyone-- except for Mr. Chen. There was no doubt he was staring right at her. Glaring.

"Undo that immediately," he said, in an extremely calm voice that did not match his reddening face.

"I, uh-- okay?" she reached for the keyboard.

"BENNY!" Mr. Chen rebuked, "Benny, you undo those changes."

Benny snatched the laptop away, and with a barrage of CTRL-Z wiped away her change.

"But-- that fixes the bug-- "

"No," Mr. Chen stated, "The CORRECT fix is to delete the second record, and inform Fiduciary Interest that their Andrew Sanders may not have access to this system until he changes his password to something unique. Then there is no code change needed."

"But but-- " Alexis stumbled, "It's a documented Microsoft bug, and if-- "

"The code of 'We Sell Bonds!' is properly and carefully written. We do not change it to conform to someone else's mistakes. This complex code change you unilaterally impose is unknown, untested, unreliable and utterly unacceptable. You would determine the course of a financial business based on an outrageous outside case?"

"But, it's happening and causing a problem now and-- "

Benny pointed at his screen, where he'd entered a query with a GROUP BY and HAVING. "Only eight usernames are duplicated like that."

"Vanishingly small," Mr. Chen said, "Benny, print out those users, and then delete them. Nadine, contact those companies and inform them those users will not have access to the website until their information is corrected. With that solved, we can all resume work."

Everyone at the company returned to their tasks. Alexis stared at her screen for a moment, at the ASP management screen that waited for her data to be entered. It didn't implement any change. It didn't introduce any progress. It was just an ASP form for data entry. And that was her job.

She entered her data.

At lunch, when everyone in the company got up to take their break, Mr. Chen motioned for her to sit back down. After the rest of the company filed out, he spoke.

"Alexis, although your ability to interface with the system is adequate, I am afraid your inability to focus on your task is not. I require a worker who is careful and proper, and you are not. Thank you for your time. You will be paid for the remainder of the day, but may go home now. I will see you out."

Alexis erred on the better side of valor, and did not shout in his face that he can't fire her, because she was quitting.

Mr. Chen ushered her out the front door, and locked it behind her.

Alexis stood on the busy sidewalk, the lunchtime crowd pushing and shoving their way past her. She looked back on the quaint, brick-faced office building. On the surface, it had been exactly what she'd wanted from her first programming job. She only got one "first" job, and it had ended up being-- that.

She wallowed for a moment, and then pulled herself back together. No. Data entry did not a programming job make. Her real first programming job was still ahead of her, somewhere. And next time, when she thought she'd found it, she would first look-- properly and carefully-- past the quaint surface to what lay beneath.

[Advertisement] Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.

https://thedailywtf.com/articles/we-sell-bonds


Метки:  

CodeSOD: The Pythonic Wheel Reinvention

Среда, 31 Января 2018 г. 14:30 + в цитатник

Starting with Java, a robust built-in class library is practically a default feature of modern programming languages. Why struggle with OS-specific behaviors, or with writing your own code, or managing a third party library to handle problems like accessing files or network resources.

One common class of WTF is the developer who steadfastly refuses to use it. They inevitably reinvent the wheel as a triangle with no axle. Another is the developer who is simply ignorant of what the language offers, and is too lazy to Google it. They don’t know what a wheel is, so they invent a coffee-table instead.

My personal favorite, though, is the rare person who knows about the class library, that uses the class library… to reinvent methods which exist in the class library. They’ve seen a wheel, they know what a wheel is for, and they still insist on inventing a coffee-table.

Anneke sends us one such method.

The method in question is called thus:

if output_exists("/some/path.dat"):
    do_something()

I want to stress, this is the only use of this method. The purpose is to check if a file containing output from a different process exists. If you’re familiar with Python, you might be thinking, “Wait, isn’t that just os.path.exists?”

Of course not.

def output_exists(full_path):
    path = os.path.dirname(full_path) + "/*"
    filename2=full_path.split('/')[-1]
    filename = '%s' % filename2
    files = glob.glob(path)
    back = []
    for f in re.findall(filename, " ".join(files)):
        back.append(os.path.join(os.path.dirname(full_path), f))
    return back

Now, in general, most of your directory-tree manipulating functions live in the os.path package, and you can see os.path.dirname used. That splits off the directory-only part. Then they throw a glob on it. I could, at this point, bring up the importance of os.path.join for that sort of operation, but why bother?

They knew enough to use os.path.dirname to get the directory portion of the path, but not os.path.split which can pick off the file portion of the path. The “Pythonic” way of writing that line would be (path, filename) = os.path.split(full_path). Wait, I misspoke: the “Pythonic” way would be to not write any part of this method.

'%s' % filename2 is how Python’s version of printf and I cannot for the life of me guess why it’s being done here. A misguided attempt at doing an strcpy-type operation?

glob.glob isn’t just the best method name in anything, it also does a filesystem search using globs, so files contains a list of all files in that directory.

" ".join(files) is the Python idiom for joining an array, so we turn the list of files into an array and search it using re.findall… which uses a regex for searching. Note that they’re using the filename for the regex, and they haven’t placed any guards around it, so if the input file is “foo.c”, and the directory contains “foo.cpp”, this will think that’s fine.

And then last but not least, it returns the array of matches, relying on the fact that an empty array in Python is false.

To write this code required at least some familiarity with three different major packages in the class library- os.path, glob, and re, but just one ounce of more familiarity ith os.path would have replaced the entire thing with a simple call to os.path.exists. Which is what Anneke did.

[Advertisement] High availability, Load-balanced or Basic – design your own Universal Package Manager, allow the enterprise to scale as you grow. Download and see for yourself!

https://thedailywtf.com/articles/the-pythonic-wheel-reinvention


Метки:  

Representative Line: As the Clock Terns

Вторник, 30 Января 2018 г. 14:30 + в цитатник

Hydranix” can’t provide much detail about today’s code, because they’re under a “strict NDA”. All they could tell us was that it’s C++, and it’s part of a “mission critical” front end package. Honestly, I think this line speaks for itself:

(mil == 999 ? (!(mil = 0) && (sec == 59 ? 
  (!(sec = 0) && (min == 59 ? 
    (!(min = 0) && (++hou)) : ++min)) : ++sec)) : ++mil);

“Hydranix” suspects that this powers some sort of stopwatch, but they’re not really certain what its role is.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/as-the-clock-terns


Метки:  

Representative Line: The Mystery of the SmallInt

Понедельник, 29 Января 2018 г. 14:30 + в цитатник

PT didn’t provide very much information about today’s Representative Line.

Clearly bits and bytes was not something studied in this SQL stored procedure author. Additionally, Source control versions are managed with comments. OVER 90 Thousand!

        --Declare @PrevNumber smallint
                --2015/11/18 - SMALLINT causes overflow error when it goes over 32000 something 
                -- - this sp errors but can only see that when
                -- code is run in SQL Query analyzer 
                -- - we should also check if it goes higher than 99999
        DECLARE @PrevNumber int         --2015/11/18

Fortunately, I am Remy Poirot, the world’s greatest code detective. To your untrained eyes, you simply see the kind of comment which would annoy you. But I, an expert, with experience of the worst sorts of code man may imagine, can piece together the entire lineage of this code.

Let us begin with the facts: no source control is in use. Version history is managed in the comments. From this, we can deduce a number of things: the database where this code runs is also where it is stored. Changes are almost certainly made directly in production.

A statue of Hercule Poirot in Belgium

Which, when those changes fail, they may only be detected when the “code is run in SQL Query Analyzer”. This ties in with the “changes in production/no source control”, but it also tells us that it is possible to run this code, have it fail, and no one notices. This means this code must be part of an unattended process, a batch job of some kind. Even an overflow error vanishes into the ether.

This code also, according to the comments, should “also check if [@PrevNumber] goes higher than 99999”. This is our most vital clue, for it tells us that the content of the value has a maximum width- more than 5 characters to represent it is a problem. This obviously means that the target system is a mainframe with a flat-file storage model.

Already, from one line and a handful of comments, we’ve learned a great deal about this code, but one need not be the world’s greatest code detective to figure out this much. Let’s see what else we can tease out.

@PrevNumber must tie to some ID in the database, likely the “last processed ID” from the previous run of the batch job. The confusion over smallint and need to enforce a five-digit limit implies that this database isn’t actually in control of its data. Either the data comes from a front-end with no validation- certainly possible- or it comes from an external system. But a value greater than 99999 isn’t invalid in the database- otherwise they could enforce that restriction via a constraint. This means the database holds data coming from and going to different places- it’s a “business integration” database.

With these clues, we can assemble the final picture of the crime scene.

In a dark corner of a datacenter are the components of a mainframe system. The original install was likely in the 70s, and while it saw updates and maintenance for the next twenty years, starting in the 90s it was put on life support. “It’s going away, any day now…” Unfortunately, huge swathes of the business depended on it and no one is entirely certain what it does. They can’t simply port business processes to a new system, because no one knows what the business processes are. They’re encoded as millions of lines of code in a dialect of COBOL no one understands.

A conga-line of managers have passed through the organization, trying to kill the mainframe. Over time, they’ve brought in ERP systems from Oracle or SAP. Maybe they’ve taken some home-grown ERP written by users in Access and tried to extend them to an enterprise solution. Worse, over the years, acquisitions come along, bringing new systems from other vendors under the umbrella of one corporate IT group.

All these silos need to talk to each other. They also have to be integrated into the suite of home-grown reporting tools, automation, and Excel spreadsheets that run the business. Shipping can only pull from the mainframe, while the P/L dashboard the executives use can only pull from SAP. At first, it’s a zoo of ETL jobs, until someone gets the bright idea to centralize it.

They launch a project, and give it a slick three-letter-acronym, like “QPR” or “LMP”. Or, since there are only so many TLAs one can invent, they probably reuse an existing one, like “GPS” or “FBI”. The goal: have a central datastore that integrates data from every silo in the organization, and then the silos can pull back out the data they want for their processes. This project has a multi-million dollar budget, and has exceeded that budget twice over, and is not yet finished.

The code PT supplied for us is but one slice of that architecture. It’s pulling data from one of those centralized tables in the business integration database, and massaging it into a format it can pass off to the mainframe. Like a murder reconstructed from just a bit of fingernail, we’ve laid bare the entire crime with our powers of observation, our experience, and our knowledge of bad code.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/the-mystery-of-the-smallint


Метки:  

Error'd: #TITLE_OF_ERRORD2#

Пятница, 26 Января 2018 г. 14:00 + в цитатник

Joe P. wrote, When I tried to buy a coffee at the airport with my contactless VISA card, it apparently thought my name was '%s'."

 

"Instead of outsourcing to Eastern Europe or the Asian subcontinent, companies should be hiring from Malta. Just look at these people! They speak fluent base64!" writes Michael J.

 

Raffael wrote, "While I can proudly say that I am working on bugs, the Salesforce Chatter site should probably consider doing the same."

 

"Wow! Thanks! Happy Null Year to you too!" Alexander K. writes.

 

Joel B. wrote, "Yesterday was the first time I've ever seen a phone with a 'License Violation'. Phone still works, so I guess there's that."

 

"They missed me so much, they decided to give me...nothing," writes Timothy.

 

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/title-of-errord2


Метки:  

The More Things Change: Fortran Edition

Четверг, 25 Января 2018 г. 14:30 + в цитатник

Technology improves over time. Storage capacity increases. Spinning platters are replaced with memory chips. CPUs and memory get faster. Moore's Law. Compilers and languages get better. More language features become available. But do these changes actually improve things? Fifty years ago, meteorologists used the best mainframes of the time, and got the weather wrong more than they got it right. Today, they have a global network of satellites and supercomputers, yet they're wrong more than they're right (we just had a snowstorm in NJ that was forecast as 2-4", but got 16" before drifting).

As with most other languages, FORTRAN also added structure, better flow control and so forth. The problem with languages undergoing such a massive improvement is that occasionally, coding styles live for a very long time.

Imagine a programmer who learned to code using FORTRAN IV (variable names up to 6 characters, integers implicitly start with "I" through "N" and reals start with any other letter - unless explicitly declared, flow control via GOTO, etc) writing a program in 2000 (using a then-current compiler but with FORTRAN IV style). Now imagine some PhD candidate coming along in 2017 to maintain and enhance this FORTRAN IV-style code with the latest FORTRAN compiler.

A.B.was working at a university with just such a scientific software project as part of earning a PhD. These are just a couple of the things that caused a few head-desk moments.

Include statements. The first variant only allows code to be included. The second allows preprocessor directives (like #define).

    INCLUDE  'path/file'

    #include 'path/file'

Variables. Since the only data types/structures originally available were character, logical, integer, real*4, real*8 and arrays, you had to shoehorn your data into the closest fit. This led to declarations sections that included hundreds of basic declarations. This hasn't improved today as people still use one data type to hold something that really should be implemented as something else. Also, while the compilers of today support encapsulation/modules, back then, everything was pretty much global.

Data structures. The only thing supported back then was multidimensional arrays. If you needed something like a map, you needed to roll your own. This looks odd to someone who cut their teeth on a version of the language where these features are built-in.

Inlining. FORTRAN subroutines support local subroutines and functions which are inlined, which is useful to provide implied visibility scoping. Prudent use allows you to DRY your code. This feature isn't even used, so the same code is duplicated over and over again inline. Any of you folks see that pattern in your new-fangled modern systems?

Joel Spolsky commented about the value of keeping old code around. While there is much truth in his words, the main problem is that the original programmers invariably move on, and as he points out, it is much harder to read (someone else's) code than to write your own; maintenance of ancient code is a real world issue. When code lives across too many language version improvements, it becomes inherently more difficult to maintain as its original form becomes more obsolete.

To give you an idea, take a look at the just the declaration section of one module that A.B. inherited (except for a 2 line comment at the top of the file, there were no comments). FWIW, when I did FORTRAN at the start of my career, I used to document the meaning of every. single. abbreviated. variable. name.

      subroutine thesub(xfac,casign,
     &     update,xret,typret,
     &     meop1,meop2,meop12,meoptp,
     &     traop1, traop2, tra12,
     &     iblk1,iblk2,iblk12,iblktp,
     &     idoff1,idoff2,idof12,
     &     cntinf,reoinf,
     &     strinf,mapinf,orbinf)
      implicit none
      include 'routes.h'
      include 'contr_times.h'
      include 'opdim.h'
      include 'stdunit.h'
      include 'ioparam.h'
      include 'multd2h.h'
      include 'def_operator.h'
      include 'def_me_list.h'
      include 'def_orbinf.h'
      include 'def_graph.h'
      include 'def_strinf.h'
      include 'def_filinf.h'
      include 'def_strmapinf.h'
      include 'def_reorder_info.h'
      include 'def_contraction_info.h'
      include 'ifc_memman.h'
      include 'ifc_operators.h'
      include 'hpvxseq.h'

      integer, parameter ::
     &     ntest = 000
      logical, intent(in) ::
     &     update
      real(8), intent(in) ::
     &     xfac, casign
      real(8), intent(inout), target ::
     &     xret(1)
      type(coninf), target ::
     &     cntinf
      integer, intent(in) ::
     &     typret,
     &     iblk1, iblk2, iblk12, iblktp,
     &     idoff1,idoff2,idof12
      logical, intent(in) ::
     &     traop1, traop2, tra12
      type(me_list), intent(in) ::
     &     meop1, meop2, meop12, meoptp
      type(strinf), intent(in) ::
     &     strinf
      type(mapinf), intent(inout) ::
     &     mapinf
      type(orbinf), intent(in) ::
     &     orbinf
      type(reoinf), intent(in), target ::
     &     reoinf

      logical ::
     &     bufop1, bufop2, buf12, 
     &     first1, first2, first3, first4, first5,
     &     msfix1, msfix2, msfx12, msfxtp,
     &     reject, fixsc1, fixsc2, fxsc12,
     &     reo12, non1, useher,
     &     traop1, traop2
      integer ::
     &     mstop1,mstop2,mst12,
     &     igmtp1,igmtp2,igmt12,
     &     nc_op1, na_op1, nc_op2, na_op2,
     &     nc_ex1, na_ex1, nc_ex2, na_ex2, 
     &     ncop12, naop12,
     &     nc12tp, na12tp,
     &     nc_cnt, na_cnt, idxres,
     &     nsym, isym, ifree, lenscr, lenblk, lenbuf,
     &     buftp1, buftp1, bftp12,
     &     idxst1, idxst2, idxt12,
     &     ioff1, ioff2, ioff12,
     &     idxop1, idxop2, idop12,
     &     lenop1, lenop2, len12,
     &     idxm12, ig12ls,
     &     mscmxa, mscmxc, msc_ac, msc_a, msc_c,
     &     msex1a, msex1c, msex2a, msex2c,
     &     igmcac, igamca, igamcc,
     &     igx1a, igx1c, igx2a, igx2c,
     &     idxms, idxdis, lenmap, lbuf12, lb12tp,
     &     idxd12, idx, ii, maxidx
      integer ::
     &     ncblk1, nablk1, ncbka1, ncbkx1, 
     &     ncblk2, nablk2, ncbka2, ncbkx2, 
     &     ncbk12, nabk12, ncb12t, nab12t, 
     &     ncblkc, nablkc,
     &     ncbk12, nabk12,
     &     ncro12, naro12,
     &     iblkof
      type(filinf), pointer ::
     &     ffop1,ffop2,ff12
      type(operator), pointer ::
     &     op1, op2, op1op2, op12tp
      integer, pointer ::
     &     cinf1c(:,:),cinf1a(:,:),
     &     cinf2c(:,:),cinf2a(:,:),
     &     cif12c(:,:),
     &     cif12a(:,:),
     &     cf12tc(:,:),
     &     cf12ta(:,:),
     &     cfx1c(:,:),cfx1a(:,:),
     &     cfx2c(:,:),cfx2a(:,:),
     &     cfcntc(:,:),cfcnta(:,:),
     &     inf1c(:),
     &     inf1a(:),
     &     inf2c(:),
     &     inf2a(:),
     &     inf12c(:),
     &     inf12a(:),
     &     dmap1c(:),dmap1a(:),
     &     dmap2c(:),dmap2a(:),
     &     dm12tc(:),dm12ta(:)

      real(8) ::
     &     xnrm, facscl, fcscl0, facab, xretls
      real(8) ::
     &     cpu, sys, cpu0, sys0, cpu00, sys00
      real(8), pointer ::
     &     xop1(:), xop2(:), xop12(:), xscr(:)
      real(8), pointer ::
     &     xbf1(:), xbf2(:), xbf12(:), xbf12(:), x12blk(:)

      integer ::
     &     msbnd(2,3), igabnd(2,3),
     &     ms12ia(3), ms12ic(3), ig12ia(3), ig12ic(3),
     &     ig12rw(3)

      integer, pointer ::
     &     gm1dc(:), gm1da(:),
     &     gm2dc(:), gm2da(:),
     &     gmx1dc(:), gmx1da(:),
     &     gmx2dc(:), gmx2da(:),
     &     gmcdsc (:), gmcdsa (:),
     &     gmidsc (:), gmidsa (:),
     &     ms1dsc(:), ms1dsa(:),
     &     ms2dsc(:), ms2dsa(:),
     &     msx1dc(:), msx1da(:),
     &     msx2dc(:), msx2da(:),
     &     mscdsc (:), mscdsa (:),
     &     msidsc (:), msidsa (:),
     &     idm1ds(:), idxm1a(:),
     &     idm2ds(:), idxm2a(:),
     &     idx1ds(:), ixms1a(:),
     &     idx2ds(:), ixms2d(:),
     &     idxdc (:), idxdsa (:),
     &     idxmdc (:),idxmda (:),
     &     lstrx1(:),lstrx2(:),lstcnt(:),
     &     lstr1(:), lstr2(:), lst12t(:)

      integer, pointer ::
     &     mex12a(:), m12c(:),
     &     mex1ca(:), mx1cc(:),
     &     mex2ca(:), mx2cc(:)

      integer, pointer ::
     &     ndis1(:,:), dgms1(:,:,:), gms1(:,:),
     &     lngms1(:,:),
     &     ndis2(:,:), dgms2(:,:,:), gms2(:,:),
     &     lngms2(:,:),
     &     nds12t(:,:), dgms12(:,:,:),
     &     gms12(:,:),
     &     lgms12(:,:),
     &     lg12tp(:,:), lm12tp(:,:,:)

      integer, pointer ::
     &     cir12c(:,:), cir12a(:,:),
     &     ci12c(:,:),  ci12a(:,:),
     &     mire1c(:),   mire1a(:),
     &     mire2c(:),   mire2a(:),
     &     mca12(:), didx12(:), dca12(:),
     &     mca1(:),  didx1(:),  dca1(:),
     &     mca2(:),  didx2(:),  dca2(:),
     &     lenstr_array(:,:,:)

c dbg
      integer, pointer ::
     &     dum1c(:), dum1a(:), hpvx1c(:), hpvx1a(:),
     &     dum2c(:), dum2a(:), hpvx2c(:), hpvx2a(:)
      integer ::
     &     msd1(ngastp,2,meop1%op%njoined),
     &     msd2(ngastp,2,meop2%op%njoined),
     &     jdx, totc, tota
c dbg

      type(graph), pointer ::
     &     graphs(:)

      integer, external ::
     &     ielsum, ielprd, imdst2, glnmp, idxlst,
     &     mxdsbk, m2ims4
      logical, external ::
     &     nxtdis, nxtds2, lstcmp,
     &     nndibk, nndids
      real(8), external ::
     &     ddot
[Advertisement] Universal Package Manager - ProGet easily integrates with your favorite Continuous Integration and Build Tools, acting as the central hub to all your essential components. Learn more today!

https://thedailywtf.com/articles/the-more-things-change-fortran-edition


Метки:  

Sponsor Post: Make Your Apps Better with Raygun

Среда, 24 Января 2018 г. 18:00 + в цитатник

I once inherited an application which had a bug in it. Okay, I’ve inherited a lot of applications like that. In this case, though, I didn’t know that there was a bug, until months later, when I sat next to a user and was shocked to discover that they had evolved a complex work-around to bypass the bug which took about twice as long, but actually worked.

“Why didn’t you open a ticket? This shouldn’t be like this.”

“Enh… it’s fine. And I hate dealing with tickets.”

In their defense, our ticketing system at that office was a godawful nightmare, and nobody liked dealing with it.

The fact is, awful ticket tracking aside, 99% of users don’t report problems in software. Adding logging can only help so much- eventually you have a giant haystack filled with needles you don’t even know are there. You have no way to see what your users are experiencing out in the wild.

But what if you could? What if you could build, test and deploy software with a real-time feedback loop on any problems the users were experiencing?

Our new sponsor, Raygun, gives you a window into the real user-experience for your software. With a few minutes of setup, all the errors, crashes, and performance issues will be identified for you, all in one tool.

You're probably using software and services today that relies on Raygun to identify when users have a poor experiences: Domino's Pizza, Coca-Cola, Microsoft and Unity all use it, along with many others.

Now’s the time to sign up. In a few minutes, you can have a build of your app with Raygun integration, and you’ll be surprised at how many issues it can identify. There’s nothing to lose with a 14-day free trial, and there are pricing options available that fit any team size.

[Advertisement] Otter allows you to easily create and configure 1,000's of servers, all while maintaining ease-of-use, and granular visibility down to a single server. Find out more and download today!

https://thedailywtf.com/articles/make-your-apps-better-with-raygun


Метки:  

All Saints' Day

Среда, 24 Января 2018 г. 14:30 + в цитатник

Cathedral Antwerp July 2015-1

Oh, PHP. It's the butt of any number of jokes in the programming community. Those who do PHP often lie and pretend they don't, just to avoid the social stigma. Today's submitter not only works in PHP, but they also freelance: the bottom of the bottom of the development hierarchy.

Last year, Ilya was working on a Joomla upgrade as well as adjusting several components on a big, obscure website. As he was poking around in the custom code, he found today's submission. You see, the website is in Italian. At the top of the page, it shows not only the date, but also the saint of the day. This is a Catholic thing: every day of the year has a patron saint, and in certain cultures, you might even be named for the saint whose day you were born on. A full list can be found on this Italian Wikipedia page.

Every day, the website was supposed to display text like "18 luglio: santi Sinforosa e sette compagni" (July 18: Sinforosa and the Seven Companions). But the code that generated this string had broken. It wasn't Ilya's task to fix it, but he chose to do so anyway, because why not?

His first suspect for where this text came from was this mess of Javascript embedded in the head:

     function getDataGiorno(){
     data = new Date();
     ora =data.getHours();
     minuti=data.getMinutes();
     secondi=data.getSeconds();
     giorno = data.getDay();
     mese = data.getMonth();
     date= data.getDate();
     year= data.getYear();
     if(minuti< 10)minuti="0"+minuti;
     if(secondi< 10)secondi="0"+secondi;
     if(year<1900)year=year+1900;
     if(ora<10)ora="0"+ora;
     if(giorno == 0) giorno = " Domenica ";
     if(giorno == 1) giorno = " Luned`i ";
     if(giorno == 2) giorno = " Marted`i ";
     if(giorno == 3) giorno = " Mercoled`i ";
     if(giorno == 4) giorno = " Gioved`i ";
     if(giorno == 5) giorno = " Venerd`i ";
     if(giorno == 6) giorno = " Sabato ";
     if(mese == 0) mese = "gennaio ";
     if(mese ==1) mese = "febbraio ";
     if(mese ==2) mese = "marzo ";
     if(mese ==3) mese = "aprile ";
     if(mese ==4) mese = "maggio ";
     if(mese ==5) mese = "giugno ";
     if(mese ==6) mese = "luglio ";
     if(mese ==7) mese = "agosto ";
     if(mese ==8) mese = "settembre ";
     if(mese ==9) mese = "ottobre ";
     if(mese ==10) mese = "novembre ";
     if(mese ==11) mese = "dicembre";
     var dt=date+" "+mese+" "+year;
     var gm =date+"_"+mese;

     return gm.replace(/^\s+|\s+$/g,""); ;
     }

     function getXMLHttp() {
     var xmlhttp = null;
     if (window.ActiveXObject) {
       if (navigator.userAgent.toLowerCase().indexOf("msie 5") != -1) {
         xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
       } else {
           xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
       }
     }
     if (!xmlhttp && typeof(XMLHttpRequest) != 'undefined') {
       xmlhttp = new XMLHttpRequest()
     }
     return xmlhttp
     }

     function elaboraRisposta() {
      var dt=getDataGiorno();
      var data = dt.replace('_',' ');
      if (dt.indexOf('1_')==0){
          dt.replace('1_','%C2%BA');
      }
       // alert("*"+dt+"*");
     var temp = new Array();
     temp = objHTTP.responseText.split(dt);
     //alert(temp[1]);

     var temp1=new Array();
     temp1=temp[1].split(":");
     temp=temp1[1].split("");


      if (objHTTP.readyState == 4) {
      santi=temp[0].split(",");
      //var app = new Array();
      //app=santi[0].split(";");
      santo=santi[0];
      //alert(santo);

        // document.write(data+" - "+santo.replace(/\/wiki\//g,"http://it.wikipedia.org/wiki/"));
        document.write(data+" - "+santo);
      }else {

      }

     }
     function loadDati() {
      objHTTP = getXMLHttp();
      objHTTP.open("GET", "calendario.html" , false);

      objHTTP.onreadystatechange = function() {elaboraRisposta()}


     objHTTP.send(null)
     }

If you've never seen Joomla before, do note that most templates use jQuery. There's no need to use ActiveXObject here.

"calendario.html" contained very familiar text: a saved copy of the Wikipedia page linked above. This ought to be splitting the text with the date, avoiding parsing HTML with regex by using String.prototype.split(), and then parsing the HTML to get the saint for that date to inject into the HTML.

But what if a new saint gets canonized, and the calendar changes? By caching a local copy, you ensure that the calendar will get out of date unless meticulously maintained. Therefore, the code to call this Javascript was commented out entirely in the including page:

https://thedailywtf.com/articles/all-saints-day


Метки:  

Coded Smorgasbord: Archive This

Вторник, 23 Января 2018 г. 14:30 + в цитатник

Michael W came into the office to a hair-on-fire freakout: the midnight jobs failed. The entire company ran on batch processes to integrate data across a dozen ERPs, mainframes, CRMs, PDQs, OMGWTFBBQs, etc.: each business unit ran its own choice of enterprise software, but then needed to share data. If they couldn’t share data, business ground to a halt.

Business had ground to a halt, and it was because the archiver job had failed to copy some files. Michael owned the archiver program, not by choice, but because he got the short end of that particular stick.

The original developer liked logging. Pretty much every method looked something like this:

public int execute(Map arg0, PrintWriter arg1) throws Exception {
    Logger=new Logger(Properties.getString("LOGGER_NAME"));
    Log=new Logger(arg1);
    .
    .
    .
catch (Exception e) {
    e.printStackTrace();
    Logger.error("Monitor: Incorrect arguments");
    Log.printError("Monitor: Incorrect arguments");
    arg1.write("In Correct Argument Passed to Method.Please Check the Arguments passed \n \r");
    System.out.println("Monitor: Incorrect arguments");
}

Sometimes, to make the logging even more thorough, the catch block might look more like this:

catch(Exception e){
    e.printStackTrace();
    Logger.error("An exception happened during SFTP movement/import. " + (String)e.getMessage());
}

Java added Generics in 2004. This code was written in 2014. Does it use generics? Of course not. Every Hashtable is stringly-typed:

Hashtable attributes;
.
.
.
if (((String) attributes.get(key)).compareTo("1") == 0 | ((String) attributes.get(key)).compareTo("0") == 0) { … }

And since everything is stringly-typed, you have to worry about case-sensitive comparisons, but don’t worry, the previous developer makes sure everything’s case-insensitive, even when comparing numbers:

if (flag.equalsIgnoreCase("1") ) { … }

And don’t forget to handle Booleans…

public boolean convertToBoolean(String data) {
    if (data.compareToIgnoreCase("1") == 0)
        return true;
    else
        return false;
}

And empty strings…

if(!TO.equalsIgnoreCase("") && TO !=null) { … }

Actually, since types are so confusing, let’s make sure we’re casting to know-safe types.

catch (Exception e) {
    Logger.error((Object)this, e.getStackTraceAsString(), null, null);
}

Yes, they really are casting this to Object.

Since everything is stringly typed, we need this code, which checks to see if a String parameter is really sure that it’s a string…

protected void moveFile(String strSourceFolder, Object strSourceObject,
                     String strDestFolder) {
    if (strSourceObject.getClass().getName().compareToIgnoreCase("java.lang.String") == 0) { … }
    …
}

Now, that all was enough to get Michael’s blood pressure up, but none of that had anything to do with his actual problem. Why did the copy fail? The logs were useless, as they were spammed with messages with no particular organization. The code was bad, sure, so it wasn’t surprising that it crashed. For a little while, Michael thought it might be the getFiles method, which was supposed to identify which files needed to be copied. It did a recursive directory search (with no depth checking, so one symlink could send it into an infinite loop) nor did it actually filter files that it didn’t care about. It just made an ArrayList of every file in the directory structure and then decided which ones to copy.

He spent some time really investigating the copy method, to see if that would help him understand what went wrong:

sourceFileLength = sourceFile.length();
newPath = sourceFile.getCanonicalPath();
newPath = newPath.replace(".lock", "");
newFile = new File(newPath);
sourceFile.renameTo(newFile);                    
destFileLength = newFile.length();
while(sourceFileLength!=destFileLength)
{
    //Copy In Progress
}
//Remy: I didn't elide any code from the inside of that while loop- that is exactly how it's written, as an empty loop.

Hey, out of curiosity, what does the JavaDoc have to say about renameTo?

Many aspects of the behavior of this method are inherently platform-dependent: The rename operation might not be able to move a file from one filesystem to another, it might not be atomic, and it might not succeed if a file with the destination abstract pathname already exists. The return value should always be checked to make sure that the rename operation was successful.

It only throws exceptions if you don’t supply a destination, or if you don’t have permissions to the files. Otherwise, it just returns false on a failure.

So… if the renameTo operation fails, the archiver program will drop into an infinite loop. Unlogged. Undetected. That might seem like the root cause of the failure, but it wasn’t.

As it turned out, the root cause was that someone in ops hit “Ok” on a security update, which triggered a reboot, disrupting all the scheduled jobs.

Michael still wanted to fix the archiver program, but there was another problem with that. He owned the InventoryArchiver.jar. There was also OrdersArchiver.jar, and HRArchiver.jar, and so on. They had all been “written” by the same developer. They all did basically the same job. So they were all mostly copy-and-paste jobs with different hard-coded strings to specify where they ran. But they weren’t exactly copy-and-paste jobs, so each one had to be analyzed, line by line, to see where the logic differences might possibly crop up.

[Advertisement] Infrastructure as Code built from the start with first-class Windows functionality and an intuitive, visual user interface. Download Otter today!

https://thedailywtf.com/articles/archive-this


Метки:  

Alien Code Reuse

Понедельник, 22 Января 2018 г. 14:30 + в цитатник

“Probably the best thing to do is try and reorganize the project some,” Tim, “Alien”’s new boss said. “It’s a bit of a mess, so a little refactoring will help you understand how the code all fits together.”

“Alien” grabbed the code from git, and started walking through the code. As promised, it was a bit of a mess, but partially that mess came from their business needs. There was a bunch of common functionality in a Common module, but for each region they did business in- Asia, North America, Europe, etc.- there was a region specific deployable, each in its own module. Each region had its own build target that would include the Common module as part of the build process.

The region-specific modules were vaguely organized into sub-modules, and that’s where “Alien” settled in to start reorganizing. Since Asia was the largest, most complicated module, they started there, on a sub-module called InventoryManagement. THey moved some files around, set up the module and sub-modules in Maven, and then rebuilt.

The Common library failed to build. This gave “Alien” some pause, as they hadn’t touched anything pertaining to the Common project. Specifically, Common failed to build because it was looking for some files in the Asia.InventoryManagement sub-module. Cue the dive into the error trace and the vagaries of the build process. Was there a dependency between Common and Asia that had gone unnoticed? No. Was there a build-order issue? No. Was Maven just being… well, Maven? Yes, but that wasn’t the problem.

After hunting around through all the obvious places, “Alien” eventually ran an ls -al.

~/messy-app/base/Common/src/com/mycompany > ls -al
lrwxrwxrwx 1 alien  alien    39 Jan  4 19:10 InventoryManagement -> ../../../../../Asia/InventoryManagement/src/com/mycompany/IM/
drwxr-x--- 3 alien  alien  4096 Jan  4 19:10 core/

Yes, that is a symbolic link. A long-ago predecessor discovered that the Asia.InventoryManagement sub-module contained some code that was useful across all modules. Acutally moving that code into Common would have involved refactoring Asia, which was the largest, most complicated module. Presumably, that sounded like work, so instead they just added a sym-link. The files actually lived in Asia, but were compiled into Common.

“Alien” writes, “This is the first time in my over–20-year working life I see people reuse source code like this.”

They fixed this, and then went hunting, only to find a dozen more examples of this kind of code “reuse”.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/alien-code-reuse


Метки:  

Error'd: Alphabetical Soup

Пятница, 19 Января 2018 г. 14:30 + в цитатник

"I appreciate that TIAA doesn't want to fully recognize that the country once known as Burma now calls itself Myanmar, but I don't think that this is the way to handle it," Bruce R. writes.

 

"MSI Installed an update - but I wonder what else it decided to update in the process? The status bar just kept going and going..." writes Jon T.

 

Paul J. wrote, "Apparently my occupation could be 'All Other Persons' on this credit card application!"

 

Geoff wrote, "So I need to commit the changes I didn't make, and my options are 'don't commit' or 'don't commit'?"

 

David writes, "This was after a 15 minute period where I watched a timer spin frantically."

 

"It's as if DealeXtreme says 'three stars, I think you meant to say FIVE stars'," writes Henry N.

 

[Advertisement] Universal Package Manager – store all your Maven, NuGet, Chocolatey, npm, Bower, TFS, TeamCity, Jenkins packages in one central location. Learn more today!

https://thedailywtf.com/articles/alphabetical-soup


Метки:  

Поиск сообщений в rss_thedaily_wtf
Страницы: 124 ... 61 60 [59] 58 57 ..
.. 1 Календарь