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

Поиск сообщений в 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 Wrapped Up

Понедельник, 09 Ноября 2015 г. 14:30 + в цитатник

PHP has a lot of warts, and one of those warts is its approach to database interactions. If you want to talk to a MySQL database, every function for doing it is prefixed mysql_, and for say, Postgres, youd use functions prefixed pg_. On the other hand, it uses an object oriented approach for talking to SQLite3, while Oracle not only has a set of oci_ prefixed functions, but has to add a bunch of important functions that make it just different enough as to be difficult to switch to.

Its a bit of a mess, is the point, and the result is that a lot of developers will write some wrapper functions to make it easier to write generic code thats not tied to a specific database engine. That is, presumably, what Scotts co-worker had in mind when building this library of wrapper functions:

function fetch_row($resource_result)
{
  // array mysql_fetch_row ( resource result)
  // Returns an array that corresponds to the fetched row, or FALSE if there are no more rows.
  return mysql_fetch_row($resource_result);
}

Yes- the wrapper function is just essentially re-naming the function to strip off the mysql prefix. And yes, Scotts co-worker did this for every method that was part of the MySql API.

Only one actually contained any logic:

function fetch_assoc($resource_result)
{
  // array mysql_fetch_assoc ( resource result)
  // Returns an associative array that corresponds to the fetched row, or FALSE if there are
  // no more rows.

    // check to see if we were sent a null resource
    if($resource_result == null){
        throw new Exception('NULL resource_result sent.');
    }

    return mysql_fetch_assoc($resource_result);

}

The rest simply contained copy-and-pasted documentation from the PHP.net documentation site:

function fetch_field($resource_result,$field_offset)
{
  // object mysql_fetch_field ( resource result [, int field_offset])
  // Returns an object containing field information.
  // mysql_fetch_field() can be used in order to obtain information about fields in a certain
  // query result. If the field offset isn't specified, the next field that wasn't yet
  // retrieved by mysql_fetch_field() is retrieved.
  return mysql_fetch_field($resource_result,$field_offset);
}

function fetch_lengths($resource_result)
{
  // array mysql_fetch_lengths ( resource result)
  // Returns an array that corresponds to the lengths of each field in the last row fetched
  // by mysql_fetch_row(), or FALSE on error.
  return mysql_fetch_lengths($resource_result);
}

function fetch_object($resource_result)
{
  // object mysql_fetch_object ( resource result)
  // Returns an object with properties that correspond to the fetched row, or FALSE if there
  // are no more rows.
  return mysql_fetch_object($resource_result);
}

function field_flags($resource_result)
{
  // string mysql_field_flags ( resource result, int field_offset)
  // mysql_field_flags() returns the field flags of the specified field. The flags are
  // reported as a single word per flag separated by a single space, so that you can split the
  // returned value using explode().
  return mysql_field_flags($resource_result);
}

function field_len($resource_result,$field_offset)
{
  // int mysql_field_len ( resource result, int field_offset)
  // mysql_field_len() returns the length of the specified field.
  return mysql_field_len($resource_result,$field_offset);
}

function field_name($resource_result,$field_offset)
{
  // string mysql_field_name ( resource result, int field_index)
  // mysql_field_name() returns the name of the specified field index. result must be a
  // valid result identifier and field_index is the numerical offset of the field.
  return mysql_field_name($resource_result,$field_offset);
}

function field_seek($resource_result,$field_offset)
{
  // int mysql_field_seek ( resource result, int field_offset)
  // Seeks to the specified field offset. If the next call to mysql_fetch_field() doesn't
  // include a field offset, the field offset specified in mysql_field_seek() will be returned.
  return mysql_field_seek($resource_result,$field_offset);
}

function field_table($resource_result,$field_offset)
{
  // string mysql_field_table ( resource result, int field_offset)
  // Returns the name of the table that the specifed field is in.
  return mysql_field_table($resource_result,$field_offset);
}

function field_type($resource_result,$field_offset)
{
  // string mysql_field_type ( resource result, int field_offset)
  // mysql_field_type() is similar to the mysql_field_name() function. The arguments are
  // identical, but the field type is returned instead. The field type will be one of "int",
  // "real", "string", "blob", and others as detailed in the MySQL documentation.
  return mysql_field_type($resource_result,$field_offset);
}

function free_result($resource_result)
{
  // bool mysql_free_result ( resource result)
  // mysql_free_result() will free all memory associated with the result identifier result.
  return mysql_free_result($resource_result);
}

function get_client_info()
{
  // string mysql_get_client_info ( void )
  // mysql_get_client_info() returns a string that represents the client library version.
  return mysql_get_client_info();
}

function get_host_info()
{
  // string mysql_get_host_info ( [resource link_identifier])
  // mysql_get_host_info() returns a string describing the type of connection in use for the
  // connection link_identifier, including the server host name. If link_identifier is omitted,
  // the last opened connection will be used.
  return mysql_get_host_into();
}

function get_proto_info()
{
  // int mysql_get_proto_info ( [resource link_identifier])
  // mysql_get_proto_info() returns the protocol version used by connection link_identifier.
  // If link_identifier is omitted, the last opened connection will be used.
  return mysql_get_proto_info();
}

function get_server_info()
{
  // string mysql_get_server_info ( [resource link_identifier])
  // mysql_get_server_info() returns the server version used by connection link_identifier. If
  // link_identifier is omitted, the last opened connection will be used.
  return mysql_get_server_info();
}

function info()
{
  // string mysql_info ( [resource link_identifier])
  // mysql_info() returns detailed information about the last query using the given
  // link_identifier. If link_identifier isn't specified, the last opened link is assumed.
  return mysql_info();
}

function insert_id()
{
  // int mysql_insert_id ( [resource link_identifier])
  // mysql_insert_id() returns the ID generated for an AUTO_INCREMENT column by the previous
  // INSERT query using the given link_identifier. If link_identifier isn't specified, the
  // last opened link is assumed.
  return mysql_insert_id();
}

function list_dbs()
{
  // resource mysql_list_dbs ( [resource link_identifier])
  // mysql_list_dbs() will return a result pointer containing the databases available from the
  // current mysql daemon. Use the mysql_tablename() function to traverse this result pointer,
  // or any function for result tables, such as mysql_fetch_array().
  return mysql_list_dbs();
}

function list_fields($database,$table)
{
  // resource mysql_list_fields ( string database_name, string table_name [, resource link_identifier])
  // mysql_list_fields() retrieves information about the given table name. Arguments are the
  // database and the table name. A result pointer is returned which can be used with
  // mysql_field_flags(), mysql_field_len(), mysql_field_name(), and mysql_field_type().
  return mysql_list_fields($database,$table);
}

function list_processes()
{
  // resource mysql_list_processes ( [resource link_identifier])
  // mysql_list_processes() returns a result pointer describing the current server threads.
  return mysql_list_processes();
}

function list_tables($database)
{
  // resource mysql_list_tables ( string database [, resource link_identifier])
  // mysql_list_tables() takes a database name and returns a result pointer much like the
  // mysql_query() function. Use the mysql_tablename() function to traverse this result
  // pointer, or any function for result tables, such as mysql_fetch_array().
  return mysql_list_tables($database);
}

function num_fields($resource_result)
{
  // int mysql_num_fields ( resource result)
  // mysql_num_fields() returns the number of fields in the result set result.
  return mysql_num_fields($resource_result);
}

function num_rows($resource_result)
{
  // int mysql_num_rows ( resource result)
  // mysql_num_rows() returns the number of rows in a result set. This command is only valid
  // for SELECT statements. To retrieve the number of rows affected by a INSERT, UPDATE or
  // DELETE query, use mysql_affected_rows().
  return mysql_num_rows($resource_result);
}

function pconnect($server,$user,$password,$client_flags=NULL)
{
  // resource mysql_pconnect ( [string server [, string username [, string password [, int client_flags]]]])
  // Returns a positive MySQL persistent link identifier on success, or FALSE on error.
  return mysql_pconnect($server,$user,$password,$client_flags);
}

function ping($resoure_link)
{
  // bool mysql_ping ( [resource link_identifier])
  // mysql_ping() checks whether or not the connection to the server is working. If it has
  // gone down, an automatic reconnection is attempted. This function can be used by scripts
  // that remain idle for a long while, to check whether or not the server has closed the
  // connection and reconnect if necessary. mysql_ping() returns TRUE if the connection to the
  // server is working, otherwise FALSE.
  return mysql_ping($resoure_link);
}


function result($resource_result,$row=0,$field=0)
{
  // mixed mysql_result ( resource result, int row [, mixed field])
  // mysql_result() returns the contents of one cell from a MySQL result set. The field
  // argument can be the field's offset, or the field's name, or the field's table dot
  // field name (tablename.fieldname). If the column name has been aliased ('select foo as
  // bar from...'), use the alias instead of the column name.
  return @mysql_result($resource_result,$row,$field);
}


function select_db($database)
{
  // bool mysql_select_db ( string database_name [, resource link_identifier])
  // Returns TRUE on success or FALSE on failure.
  return mysql_select_db($database);
}

function db_stat()
{
  // string mysql_stat ( [resource link_identifier])
  // mysql_stat() returns the current server status.
  // Note: mysql_stat() currently only returns status for uptime, threads, queries,
  // open tables, flush tables and queries per second. For a complete list of other status
  // variables you have to use the SHOW STATUS SQL command.
  return mysql_stat();
}

function tablename($resource_result,$index)
{
  // string mysql_tablename ( resource result, int i)
  // mysql_tablename() takes a result pointer returned by the mysql_list_tables() function as
  // well as an integer index and returns the name of a table. The mysql_num_rows() function may
  // be used to determine the number of tables in the result pointer. Use the mysql_tablename()
  // function to traverse this result pointer, or any function for result tables, such as
  // mysql_fetch_array().
  return mysql_tablename($resource_result,$index);
}

function thread_id()
{
  // int mysql_thread_id ( [resource link_identifier])
  // mysql_thread_id() returns the current thread ID. If the connection is lost and you
  // reconnect with mysql_ping(), the thread ID will change. This means you should not get the
  // thread ID and store it for later. You should get it when you need it.
  return mysql_thread_id();
}

function unbuffered_query($string)
{
  // resource mysql_unbuffered_query ( string query [, resource link_identifier])
  // mysql_unbuffered_query() sends a SQL query query to MySQL, without fetching and buffering
  // the result rows automatically, as mysql_query() does. On the one hand, this saves a
  // considerable amount of memory with SQL queries that produce large result sets. On the other
  // hand, you can start working on the result set immediately after the first row has been
  // retrieved: you don't have to wait until the complete SQL query has been performed. When
  // using multiple DB-connects, you have to specify the optional parameter link_identifier.
  return mysql_unbuffered_query($string);
}
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

http://thedailywtf.com/articles/all-wrapped-up


Метки:  

Error'd: In Memoriam

Пятница, 06 Ноября 2015 г. 14:00 + в цитатник

"I went to get my stuff off the printer at work but it appeared to have passed," writes Kelly B..

"50% off means it's free? Thanks Steam!" writes James C.

"Are you sure this isn't a discount on 'laser data removal'?," wrote Matt F.

"I'm sure that LG makes great TVs, just perfect for displaying errors," Peter S. wrote.

Lucian H. writes, "Come on Github, why do you have to act so...unfashionable?"

"I saw this right after getting my free Windows 10 upgrade," writes Dave F., "I'm pretty sure the recommendation to change the resolution to accommodate the 50+ Microsoft Office Upload Center icons constitutes treating the symptom."

"Sure, they're reusable, but you do get a slight discount when you buy 300," Ryan F. wrote.

"you know, it figures that you'd get an error when trying to divide something by potato," wrote Bryan B.

[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an impressively-featured free edition, too!

http://thedailywtf.com/articles/in-memoriam


Метки:  

Featurette: Puppet Labs

Четверг, 05 Ноября 2015 г. 14:30 + в цитатник

As we announced a few months back, Puppet Labs is one of our sponsors. As part of that arrangement, I got to go behind the scenes and learn a little bit about how things work at Puppet Labs.

Puppet Logo

I got to have a conversation with Stephanie Stouck, a product marketing manager, as well as Eric Sorensen, their technical product manager. Erics a long-time sysadmin who migrated from being a customer of Puppet and its competitors into being someone who makes Puppet. Stephanie comes from a background in product marketing, but gets to see how customers are using Puppet.

Before we get into that, though, lets get the important question out of the way. Puppet Labs is based in Portland. Hows the office coffee? Delicious! according to Stephanie. We have a kind of ridiculous coffee culture, Eric says. I feel at least partially responsible. He should- hes the star of Puppets internal training video on how to care for their espresso machine.

Puppet is one of the big products at the center of the DevOps space. DevOps, like the cloud, and agile, is a term everyone uses, but no one can accurately define. I gave Stephanie and Eric a chance to nail the term down.

DevOps is as much a cultural shift, Stephanie explains, as it is a set of work practices. Its not a specific set of tools, techniques, or practices, but more a goal: DevOps means development and operations teams are aligned around a single business goal- to deliver value to customers.

Eric expands on that alignment. Its sharing technology thats taken for granted on one side of the dev/ops divide and implementing it in a new way… for example, bringing pervasive version control and CI from the dev world and applying it to infrastructure code; conversely, taking the idea of monitoring every metric and instrumenting the application to expose those metrics from day one.

This all feels very warm and fuzzy, but lets get down to brass tacks. I dont want to end up being the subject of an article on TDWTF. How does Puppet help with that? Eric has a strong opinion:

TESTING! There are a bunch of awesome test features in Puppet that let you do everything from try out your changes on a disposable VM before checking them in, to running on a production server in dry run / no-op mode so you know before you flip the switch whether things are going to work or not. Know before you go!

In fact, Eric points out that they eat their own dogfood. Its these testing tools that let them get Puppet out the door.

They use Beaker, along with rspec-puppet. You can say things like, bring up a Centos master, point a Windows agent at it, compile a catalog, and make sure the agent gets a resource that looks a certain way.

He adds, If youre not using configuration management automation, life gets better. If youre using config management you wrote yourself, or that someone else wrote and then left the company… life really gets better.

True Confession: I built an automated deployment tool, and then left the company once. This was the sort of company that wanted to automate, but didnt want to spend money on buying something, nor would they ever contemplate letting dev and ops work closely together. And yes, I did over-engineer it some, and even reinvented full duplex web service calls in the process. Im not proud. Hopefully my former coworkers will be able to say it gets better, eventually.

Now, Puppet has a huge install base, but I wanted to know: what are some cool things happening with the tool?

A great example is GitHub, Stephanie says. They have grown exponentially over the past 5 years. Puppet has really helped by allowing them to scale.

I built out the infrastructure for the iCloud service on Puppet, Eric adds. iCloud was a brand-new greenfield service and we were able to start out with the premise that everything everything had to be in Puppet. We got several thousand Linux boxes provisioned and configured, so when we flipped the switch on day one, it was awesome to see the subscribers just start filling up this big empty data center.

One of my favorite stories is Ambit Energy, Stephanie adds. Ambit couldnt deploy fast enough to support their rapid growth. It was taking too long to develop and deploy applications with one-off scripts and manual deployment…. With Puppet, deployments are 1,200+ times more frequent. Also, the IT team can manage 500+ servers, up from only 30. Thats with the same size team.

With all of this snazzy, sunshine-y stuff, I have to dig deeper. Eric and Stephanie have been in and around the industry for a long time. They must have seen or been responsible for some serious WTFs. Whats the worst WTF theyve ever committed?

Worst WTF was probably back in my ISP days; I was trying to add an IP alias to the main shell server and instead changed its actual IP. I sprinted for the server room faster than Ive ever run before.  Eric

Do home improvement hacks count? Back in my rental days I came up with a great hack to make my wool rug slip proof. It was genius! Why spend money on a pricey rug pad. Right? Let’s just say I used the wrong adhesive. That rug was going nowhere and probably still has gone nowhere to this day.  Stephanie

What about their worst gig? Stephanie cant come up with any complaints, but Eric recalls his worst job. It was a contingency job to help out with some helpdesk software that never got installed. I hacked on my window managers config for three months solid.

Pretty much every job would be better without dealing with customers. Without naming names, whats the worst thing theyve seen around automation tools? Usually, the misuse I hear about, Stephanie says, is not using any automation at all.

The biggest issue Eric sees is people misunderstanding what the Puppet philosophy is about. People ask pretty frequently how to be reactive to some state on the node in their manifests. Like, how can I do one thing if a package is installed, and another if its not? The model is much more, you tell the node whether or not the package should be installed.

And what about inside of Puppet itself? Sure, its mostly open source, but its a project of real size. There must be some part of the system that they hope nobody looks too closely at.

puppet help help help help help, Eric says. I, of course, have to pop into the command line to run that. Running 'puppet help help help help help' outputs an ASCII art image with the caption, 'Relax, today is the first day of the rest of your life', and a brief error about misusing the command.

Aside from potentially fixing that help screen, whats next for Puppet? Stephanie explains. In October, we announced Puppet Application Orchestration, which is a new way to… orchestrate the deployment and management of business-critical infrastructure and applications. This is going to be generally available later this year, part of Puppet Enterprise 2015.3. You can find out more by checking out CEO Luke Kanies keynote from PuppetConf 2015.

Finally, I reminded Eric and Stephanie that this is a humor site. They both offered their own short jokes to contribute:

If at first you don’t succeed, call it version 1.0, Stephanie contributed.

They kicked me out of karaoke for trying to sing Danger Zone five times in a row& They said Id exceeded the maximum number of Loggins attempts, Eric added.

With all of that said, you can take a crack at Puppet's free trial. As someone who promotes laziness, if you aren't using some kind of automation, you really should be.

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

http://thedailywtf.com/articles/featurette-puppet-labs


Метки:  

CodeSOD: Circle Space

Среда, 04 Ноября 2015 г. 14:30 + в цитатник

Are you satisfied with your service today?

Answer a brief survey and enter to win a New* IPAD!!!!**

AFT-v2-CallToAction-Survey

The nice thing about working in an outsourced development firm was that the type of work varied from day to day. One client might want an eCommerce website, while the next wanted an app to plug into their eCommerce site, and the next wanted to set their old eCommerce site on fire and replace it with WordPress. Endless variety!

The downside, of course, was that sometimes the assignments were ... less than glamorous. Today's client was a repeat customer, but since the original dev had left the company, Jason received the assignment to update their customer satisfaction survey. It should've been simple, just a layout tweak and adding some new questions.

Taking a look under the hood, Jason found a kludge of technologies: Ruby on Rails, generating PHP, which would then be interpreted into HTML and served to the customer, where it'd be picked apart and updated in JavaScript. When a user finished answering survey questions, a PDF was generated by overlaying circles on a static form that had been scanned in from their original, paper solution.

On the form, each question had an initial bounding text box where the question and the answer checkboxes were defined. To ensure that the marks were placed in exactly the right spot, the developer had tweaked the font sizes in each text box, and used a series of spaces to adjust the horizontal position before printing a Unicode circle. It had been a laborous task of trial and error, and clearly the previous developer had gotten far too clever: not only did he use the standard space character you can type from your keyboard, but he also used "full-width spaces" to span larger gaps, dropping to normal ones for fine tweaking.

"purpose" => array(     //Q1
        "width" => 150,
        "height" => 30,
        "x" => 9,
        "y" => 83,
        "size" => 18,
        "sample" => "

http://thedailywtf.com/articles/circle-space


Метки:  

Self Service

Вторник, 03 Ноября 2015 г. 14:30 + в цитатник

Annas employer made billing software for energy companies, and they had just entered into an exciting time: the Dutch utility market was loosening its regulations, and that meant a flood of startups were looking for a cheap way to bill their customers. Of course, their product was designed for the US market, not the Dutch market, but the CEO didnt see that as a problem. No worries, he would say, Annas our top notch configurator, and shell customize it for you in no time.

Electrical Hazard (wiring)

This, of course, was news to Anna, who didnt actually know anything about the configuration of the software. After a one-day training session, she was officially declared the expert, and sent off to sink or swim- and she mostly swam. There were a lot of options in the package, and it was extensible through add-ons, which meant Anna spent a lot of time whipping together one-off modules for each customers deployment.

During this period, one of her favorite customers was Joep. Joep had needs. Joep had a lot of needs. He was polite, and friendly, and Anna liked Joep, but Joep tended to start every conversation with, You know, itd be nice if… and then invent a thousand new requirements for the billing package.

A lot of them were around reporting, which was not the systems strong suit. Joep wanted the ability to run ad hoc reports against any dataset his mind could imagine. How many left-handed customers logged into the billing application between 2:04AM and 2:37AM and were also watching something on Youtube?

This lead to a lot of screen-sharing sessions and on one of those calls, Anna fired up Toad to connect to the back end database.

Oh! Whats that? Joep asked, as she typed in a query.

Im just trying to see if weve got the data wed need to build your report.

And you can type commands… to build custom queries?

Yes… And Anna was seduced by temptation. Joep wanted a lot of custom reports, and if she showed him how to use Toad and introduced him to basic SELECT statements, hed be able to self service, and that would save her a lot of headaches. So Anna helped him install Toad, disable the auto-commit functionality, and showed him how to write SELECT statements. Joep was happy, and Anna fielded far fewer calls from him.

Time passed. Anna moved on to work with other customers, Joep changed jobs, and roughly a year later, their paths crossed again. Annas latest client was Joeps new employer. They shared a laugh, reminisced about old times, and then talked about Joeps new needs.

This time, they had a SQL Server back-end, which didnt really change much about how the billing package worked. Anna noted that, and started gathering requirements for the new batch of add-ons and custom screens shed need to build. While she was concentrating on that, Joep asked, I was looking at SQL Server, and Microsofts management tools look even nicer than Toad. Do you think I could use those?

Sure, I guess, Anna said, without really thinking about it. Over the next few weeks, she got Joeps new company set up and configured to their liking, and moved on to the next client.

Months later, this email arrived:

From: joep@wtfinc.com
Subject: FIIIRRREEEE!!!!!!!!!!!!!
CALL. ME. NOW.

Anna called. Joep picked the phone up before Anna even heard it the ringtone, and screamed, WHERE IS THE ROLLBACK? HOW DO I ROLLBACK? ARGHTNHR!

Anna, of course, had only taught Joep about the SELECT statement, but Joep was a smart guy. He went on to learn all about commands like UPDATE, DELETE and TRUNCATE. Joep liked to run hypothetical reports from Toad, by altering the data. When she had him setup Toad, she was very clear on how to prevent Toad from auto-committing changes.

The SQL Server Management Studio, and SQL Server in general, defaults to automatically committing each statement.

I was just trying to get rid of the test accounts, Joep sobbed.

Anna got Joep to share his screen, and tried to understand what had happened. Joep had gotten in the habit of running commands in SSMS by selecting the statement he wanted to run and hitting F5, and this time he got a little sloppy with the mouse- instead of selecting every line in:

DELETE FROM customers
WHERE account_name LIKE "TEST_%"

He only selected the first line. 12,000 customers were wiped out in an instant. There was little Anna could do- she sent him off to talk to their DBAs. Even after restoring from backup and reviewing the logs from the web application, they lost somewhere between 1,000 and 2,000 customers.

And so, Joep moved on to his next job.

[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!

http://thedailywtf.com/articles/self-service


Метки:  

CodeSOD: Bonus WTF: Happy Birthday, George Boole

Вторник, 03 Ноября 2015 г. 00:30 + в цитатник
Today is George Boole's 200th Birthday. We've rerun this classic many times, but I can't think of a better time to reshare it! - Remy

The problem with "logic" is that it makes things out to be nothing but simple dualities. Proponents of logic want us to believe that everything is true or false, black or white, yes or no, paper or plastic, etc. Thankfully, there are some among us, like Mark Harrison's colleague, who are not afraid to stand up to these logic advocates and shout "no, I will not succumb to your false dichotomies!" Today, I think we all should salute those few brave people ...

enum Bool 
{ 
    True, 
    False, 
    FileNotFound 
};
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!

http://thedailywtf.com/articles/bonus-wtf-happy-birthday-george-boole


Метки:  

CodeSOD: Shadow Over XML

Понедельник, 02 Ноября 2015 г. 14:30 + в цитатник

Halloween may be over, but its always a good time for a horror story.

Like many horror stories, Nicks starts with a mysterious inheritance from a long-gone predecessor. This tool manages student data, and it needs to pull data from documents in Microsoft Word XML, using C#.

The escalation of any horror story moves in small increments. First, you notice things that are a little off, like this method signature:

private void processAllHiddenTags(StringBuilder sbXMLString, ASMStudent student)

A StringBuilder object to hold an XML String? That cant be right. But then, just below that, comes a different twist:

    int num = 0;
    int tempNumber2 = 0;
    int tempNumber3 = 0;
    int tempNumber4 = 0;
    int tempNumber5 = 0;
    int tempNumber6 = 0;
    int tempNumber7 = 0;
    int tempNumber8 = 0;
    int tempNumber9 = 0;
    object iD = student.ID;

Oh, thats worrying. And in fact, elsewhere in the code, we start seeing declarations of variables like tempStr3 and tempStr4 and tempNumber12. Its already clear that somethings gone terribly wrong here. If we were smart, we would turn back, get out of this crazy function, and go someplace else. But our curiosity is too strong. We keep pressing onward…

    if (((sbXMLString.ToString().IndexOf("") >= 0) && (sbXMLString.ToString().IndexOf("") <= sbXMLString.Length)) && ((((sbXMLString.ToString().IndexOf("") - sbXMLString.ToString().IndexOf("")) + 9) >= 0) && (((sbXMLString.ToString().IndexOf("") - sbXMLString.ToString().IndexOf("")) + 9) <= sbXMLString.Length)))
        {
            pageText = sbXMLString.ToString().Substring(sbXMLString.ToString().IndexOf(""), (sbXMLString.ToString().IndexOf("") - sbXMLString.ToString().IndexOf("")) + 9).ToString().Trim();
        }

And like a jump scare, this leaps out of the closet at us. Its starting to dawn on us, maybe the person who initially developed this… never used any XML parsing libraries at all. Maybe they tried to parse the entire thing with IndexOfs…

How long is this function anyway? Oh, its 425 lines? Oh… oh no.

                            for (int tempNumber24 = 0; tempNumber24 < list.Count; tempNumber24++)
                            {
                                tempList4.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList2.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList3.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList5.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList6.Add(sbXMLString.ToString().IndexOf("", list[tempNumber24]));
                            }

Oh, oh thats awful. But at least… theyre not using Regexes to parse XML, right? Nobody would parse XML with a regular expression, would they?

                tempStr4 = tempStr4.ToString().Trim();
                Regex pattern3 = new Regex("<<Result:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern4 = new Regex(this.sbResultRegEx.ToString());
                Regex pattern5 = new Regex("<<ResultDesc:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern6 = new Regex(this.sbResultDescRegEx.ToString());
                Regex pattern7 = new Regex("‡DataValue=<<Result:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern8 = new Regex(this.sbGraphResultRegEx.ToString());
                Regex pattern9 = new Regex("<<GroupResult:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern10 = new Regex(this.sbGroupResultRegEx.ToString());
                Regex pattern11 = new Regex("<<Class:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern12 = new Regex(this.sbClassTagRegex.ToString());
                Regex pattern13 = new Regex("<<ClassTeacher:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern14 = new Regex(this.sbClassTeacherTagRegex.ToString());
                Regex pattern15 = new Regex("<<LessonAttendance:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern16 = new Regex(this.sbLessonAttendanceRegEx.ToString());
                Regex pattern17 = new Regex("<<MinutesLate:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern18 = new Regex(this.sbMinutesLateRegEx.ToString());
                Regex pattern19 = new Regex("<<ClassesLate:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern20 = new Regex(this.sbClassesLateRegEx.ToString());
                Regex pattern21 = new Regex("<<Behaviour Points>>");
                Regex pattern22 = new Regex("<<Achievement Points>>");

Oh…. What is this sound… its singing? No, its chanting. Its beautiful and terrifying… Ia! Ia! Cthulhu Fhtagn! Ia! Ia!

Ahem. Presented for maximum suffering, the entirety of this function. Beware, for madness lies within.

/*
    And here we have entry 3+7i in the 'Why processing XML using Regexes, string manipulation functions and blind faith will land you a nice seat in the special hell' list.
*/
private void processAllHiddenTags(StringBuilder sbXMLString, ASMStudent student)
{
    int num = 0;
    int tempNumber2 = 0;
    int tempNumber3 = 0;
    int tempNumber4 = 0;
    int tempNumber5 = 0;
    int tempNumber6 = 0;
    int tempNumber7 = 0;
    int tempNumber8 = 0;
    int tempNumber9 = 0;
    object iD = student.ID;
    if (sbXMLString.ToString().IndexOf("") > 0)
    {
        string input = "";
        string pageText = string.Empty;
        if (((sbXMLString.ToString().IndexOf("") >= 0) && (sbXMLString.ToString().IndexOf("") <= sbXMLString.Length)) && ((((sbXMLString.ToString().IndexOf("") - sbXMLString.ToString().IndexOf("")) + 9) >= 0) && (((sbXMLString.ToString().IndexOf("") - sbXMLString.ToString().IndexOf("")) + 9) <= sbXMLString.Length)))
        {
            pageText = sbXMLString.ToString().Substring(sbXMLString.ToString().IndexOf(""), (sbXMLString.ToString().IndexOf("") - sbXMLString.ToString().IndexOf("")) + 9).ToString().Trim();
        }
        pageText = this.getBodyTextForEachPage(pageText, "w:sectPr");
        pageText = this.getBodyTextForEachPage(pageText, "w:pict");
        MatchCollection matchs = new Regex("").Matches(pageText);
        for (int i = 0; i < matchs.Count; i++)
        {
            if (pageText.IndexOf("") > 0)
            {
                string tempStr3 = "";
                string tempStr4 = "";
                input = string.Empty;
                int index = pageText.IndexOf("");
                int tempNumber12 = pageText.IndexOf("");
                if (((index >= 0) && (index <= pageText.Length)) && ((((tempNumber12 - index) + 6) >= 0) && (((tempNumber12 - index) + 6) < pageText.Length)))
                {
                    input = pageText.Substring(index, (tempNumber12 - index) + 6).ToString().Trim();
                }
                tempStr3 = input;
                MatchCollection patternMatches2 = new Regex("").Matches(tempStr3);
                for (int j = 0; j < patternMatches2.Count; j++)
                {
                    if (tempStr3.IndexOf("") > 0)
                    {
                        string tempStr5 = string.Empty;
                        if (((tempStr3.IndexOf("") >= 0) && (tempStr3.IndexOf("") <= tempStr3.Length)) && ((((tempStr3.IndexOf("") - tempStr3.IndexOf("")) + 6) >= 0) && (((tempStr3.IndexOf("") - tempStr3.IndexOf("")) + 6) <= tempStr3.Length)))
                        {
                            tempStr5 = tempStr3.Substring(tempStr3.IndexOf(""), (tempStr3.IndexOf("") - tempStr3.IndexOf("")) + 6);
                        }
                        tempStr3 = tempStr3.Remove(tempStr3.IndexOf(tempStr5), tempStr5.Length);
                        tempStr4 = (tempStr4 + tempStr5.Replace("", "")).Replace("", "");
                    }
                }
                tempStr4 = tempStr4.ToString().Trim();
                Regex pattern3 = new Regex("<<Result:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern4 = new Regex(this.sbResultRegEx.ToString());
                Regex pattern5 = new Regex("<<ResultDesc:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern6 = new Regex(this.sbResultDescRegEx.ToString());
                Regex pattern7 = new Regex("‡DataValue=<<Result:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern8 = new Regex(this.sbGraphResultRegEx.ToString());
                Regex pattern9 = new Regex("<<GroupResult:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern10 = new Regex(this.sbGroupResultRegEx.ToString());
                Regex pattern11 = new Regex("<<Class:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern12 = new Regex(this.sbClassTagRegex.ToString());
                Regex pattern13 = new Regex("<<ClassTeacher:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern14 = new Regex(this.sbClassTeacherTagRegex.ToString());
                Regex pattern15 = new Regex("<<LessonAttendance:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern16 = new Regex(this.sbLessonAttendanceRegEx.ToString());
                Regex pattern17 = new Regex("<<MinutesLate:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern18 = new Regex(this.sbMinutesLateRegEx.ToString());
                Regex pattern19 = new Regex("<<ClassesLate:[[\\\x00b7\\]*0-9 a-zA-Z\\\\+~`’”“'_\\(\\^\\|\\)\\[\\]\\{\\}=\\\"\\/<:>@#\\*\\$%&\\.;!?– ,-]+?>>");
                Regex pattern20 = new Regex(this.sbClassesLateRegEx.ToString());
                Regex pattern21 = new Regex("<<Behaviour Points>>");
                Regex pattern22 = new Regex("<<Achievement Points>>");
                if (pattern8.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches3 = pattern7.Matches(input);
                    for (int n = 0; n < patternMatches3.Count; n++)
                    {
                        object obj3 = null;
                        if ((tempNumber3 < this.GraphResultTags.Count) && (this.GraphResultTags.Count > 0))
                        {
                            obj3 = this.GraphResultTags[tempNumber3].HashTableStudents[iD];
                            if (obj3 != null)
                            {
                                obj3 = obj3.ToString().Replace("=", "");
                            }
                            if (patternMatches3[n].Value.Length >= 11)
                            {
                                sbXMLString.Replace(patternMatches3[n].Value.Substring(11, patternMatches3[n].Value.Length - 11), obj3);
                            }
                        }
                        tempNumber3++;
                    }
                }
                else if (pattern4.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches4 = pattern3.Matches(input);
                    for (int tempNumber15 = 0; tempNumber15 < patternMatches4.Count; tempNumber15++)
                    {
                        object obj4 = null;
                        if ((num < this.ResultTags.Count) && (this.ResultTags.Count > 0))
                        {
                            obj4 = this.ResultTags[num].HashTableStudents[iD];
                        }
                        if (obj4 != null)
                        {
                            List list = new List();
                            List tempList2 = new List();
                            List tempList3 = new List();
                            List tempList4 = new List();
                            List tempList5 = new List();
                            List tempList6 = new List();
                            int item = -1;
                            int startIndex = -1;
                            int tempNumber18 = -1;
                            int tempNumber19 = -1;
                            int tempNumber20 = -1;
                            string tempStr6 = string.Empty;
                            string tempStr7 = string.Empty;
                            object obj5 = null;
                            string tempStr8 = string.Empty;
                            string tempStr9 = string.Empty;
                            obj5 = this.ResultTags[num].HashTableResultColour[obj4];
                            if ((obj5 != null) && (Convert.ToInt32(obj5) != 0))
                            {
                                tempStr8 = ColorTranslator.ToHtml(Color.FromArgb((int) obj5));
                            }
                            startIndex = sbXMLString.ToString().IndexOf(patternMatches4[tempNumber15].Value);
                            if (startIndex >= 0)
                            {
                                tempNumber18 = sbXMLString.ToString().LastIndexOf("", startIndex);
                                tempNumber19 = sbXMLString.ToString().LastIndexOf("", startIndex);
                                tempNumber20 = sbXMLString.ToString().LastIndexOf("", startIndex);
                            }
                            if (((tempNumber18 - tempNumber19) - 5) > 0)
                            {
                                tempStr6 = sbXMLString.ToString().Substring(tempNumber19 + 5, (tempNumber18 - tempNumber19) - 5);
                            }
                            if (((tempNumber19 - tempNumber20) - 5) > 0)
                            {
                                tempStr7 = sbXMLString.ToString().Substring(tempNumber20 + 5, (tempNumber19 - tempNumber20) - 5);
                            }
                            MatchCollection patternMatches5 = new Regex("").Matches(tempStr7);
                            for (int tempNumber21 = 0; tempNumber21 < patternMatches5.Count; tempNumber21++)
                            {
                                int tempNumber22 = tempStr7.IndexOf("");
                                int tempNumber23 = tempStr7.IndexOf("");
                                if (tempNumber22 > 0)
                                {
                                    string tempStr10 = string.Empty;
                                    if (((tempNumber22 >= 0) && (tempNumber22 <= tempStr7.Length)) && ((((tempNumber23 - tempNumber22) + 6) >= 0) && (((tempNumber23 - tempNumber22) + 6) <= tempStr7.Length)))
                                    {
                                        tempStr10 = tempStr7.Substring(tempNumber22, (tempNumber23 - tempNumber22) + 6);
                                    }
                                    tempStr7 = tempStr7.Remove(tempStr7.IndexOf(tempStr10), tempStr10.Length);
                                }
                            }
                            while (true)
                            {
                                item = sbXMLString.ToString().IndexOf(patternMatches4[tempNumber15].Value, (int) (item + 1));
                                if (item < 0)
                                {
                                    break;
                                }
                                list.Add(item);
                            }
                            for (int tempNumber24 = 0; tempNumber24 < list.Count; tempNumber24++)
                            {
                                tempList4.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList2.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList3.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList5.Add(sbXMLString.ToString().LastIndexOf("", list[tempNumber24]));
                                tempList6.Add(sbXMLString.ToString().IndexOf("", list[tempNumber24]));
                            }
                            if (this.IndividualReport.PrintResultColour && (tempStr8 != null))
                            {
                                int tempNumber25 = -1;
                                for (int tempNumber26 = 0; tempNumber26 < tempList3.Count; tempNumber26++)
                                {
                                    if (((tempList5[tempNumber26] >= 0) && (tempList6[tempNumber26] >= 0)) && ((list[tempNumber26] > tempList5[tempNumber26]) && (list[tempNumber26] < tempList6[tempNumber26])))
                                    {
                                        tempNumber25++;
                                        tempStr9 = "";
                                        sbXMLString.Insert(tempList3[tempNumber26] + (tempStr9.Length * tempNumber25), tempStr9);
                                    }
                                }
                            }
                            obj4 = obj4.ToString().Substring(0, obj4.ToString().LastIndexOf("~"));
                            obj4 = obj4.ToString().Substring(obj4.ToString().IndexOf("~") + 1, obj4.ToString().Length - (obj4.ToString().IndexOf("~") + 1));
                            sbXMLString.Replace(patternMatches4[tempNumber15].Value, "\x00a7" + obj4.ToString().Trim().Replace("\n", "" + tempStr7 + "" + tempStr6 + "") + "\x00a7");
                        }
                        else
                        {
                            sbXMLString.Replace(patternMatches4[tempNumber15].Value, "\x00a7NULL\x00a7");
                        }
                        num++;
                    }
                }
                if (pattern6.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches6 = pattern5.Matches(input);
                    for (int tempNumber27 = 0; tempNumber27 < patternMatches6.Count; tempNumber27++)
                    {
                        object obj6 = null;
                        if ((tempNumber2 < this.ResultDescTags.Count) && (this.ResultDescTags.Count > 0))
                        {
                            obj6 = this.ResultDescTags[tempNumber2].HashTableStudents[iD];
                        }
                        if (obj6 == null)
                        {
                            goto donull;
                        }
                        List tmepList7 = new List();
                        List tempList8 = new List();
                        List tempList9 = new List();
                        List tempList10 = new List();
                        List tempList11 = new List();
                        List tempList12 = new List();
                        object obj7 = null;
                        string tempStr11 = string.Empty;
                        int tempNumber28 = -1;
                        string tempStr12 = string.Empty;
                        obj7 = this.ResultDescTags[tempNumber2].HashTableResultColour[obj6];
                        if ((obj7 != null) && (Convert.ToInt32(obj7) != 0))
                        {
                            tempStr11 = ColorTranslator.ToHtml(Color.FromArgb((int) obj7));
                        }
                    gohere:
                        tempNumber28 = sbXMLString.ToString().IndexOf(patternMatches6[tempNumber27].Value, (int) (tempNumber28 + 1));
                        if (tempNumber28 >= 0)
                        {
                            tmepList7.Add(tempNumber28);
                            goto gohere;
                        }
                        for (int tempNumber29 = 0; tempNumber29 < tmepList7.Count; tempNumber29++)
                        {
                            tempList10.Add(sbXMLString.ToString().LastIndexOf("", tmepList7[tempNumber29]));
                            tempList8.Add(sbXMLString.ToString().LastIndexOf("", tmepList7[tempNumber29]));
                            tempList9.Add(sbXMLString.ToString().LastIndexOf("", tmepList7[tempNumber29]));
                            tempList11.Add(sbXMLString.ToString().LastIndexOf("", tmepList7[tempNumber29]));
                            tempList12.Add(sbXMLString.ToString().IndexOf("", tmepList7[tempNumber29]));
                        }
                        if (this.IndividualReport.PrintResultColour && (tempStr11 != null))
                        {
                            int tempNumber30 = -1;
                            for (int tempNumber31 = 0; tempNumber31 < tempList9.Count; tempNumber31++)
                            {
                                if (((tempList11[tempNumber31] >= 0) && (tempList12[tempNumber31] >= 0)) && ((tmepList7[tempNumber31] > tempList11[tempNumber31]) && (tmepList7[tempNumber31] < tempList12[tempNumber31])))
                                {
                                    tempNumber30++;
                                    tempStr12 = "";
                                    sbXMLString.Insert(tempList9[tempNumber31] + (tempStr12.Length * tempNumber30), tempStr12);
                                }
                            }
                        }
                        obj6 = obj6.ToString().Substring(0, obj6.ToString().LastIndexOf("~"));
                        obj6 = obj6.ToString().Substring(obj6.ToString().IndexOf("~") + 1, obj6.ToString().Length - (obj6.ToString().IndexOf("~") + 1));
                        sbXMLString.Replace(patternMatches6[tempNumber27].Value, "\x00a7" + obj6.ToString().Trim() + "\x00a7");
                        goto end;
                    donull:
                        sbXMLString.Replace(patternMatches6[tempNumber27].Value, "\x00a7NULL\x00a7");
                    end:
                        tempNumber2++;
                    }
                }
                if (pattern10.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches7 = pattern9.Matches(input);
                    for (int tempNumber32 = 0; tempNumber32 < patternMatches7.Count; tempNumber32++)
                    {
                        sbXMLString.Replace(patternMatches7[tempNumber32].Value, "\x00a7" + this.GroupResultTags[tempNumber4].GroupResultValue.ToString().Trim() + "\x00a7");
                        tempNumber4++;
                    }
                }
                if (pattern12.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches8 = pattern11.Matches(input);
                    for (int tempNumber33 = 0; tempNumber33 < patternMatches8.Count; tempNumber33++)
                    {
                        object obj8 = null;
                        if ((tempNumber5 < this.ClassTags.Count) && (this.ClassTags.Count > 0))
                        {
                            obj8 = this.ClassTags[tempNumber5].HashTableStudents[iD];
                        }
                        if (obj8 != null)
                        {
                            sbXMLString.Replace(patternMatches8[tempNumber33].Value, obj8.ToString().Trim());
                        }
                        else
                        {
                            sbXMLString.Replace(patternMatches8[tempNumber33].Value, " ");
                        }
                        tempNumber5++;
                    }
                }
                if (pattern14.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches9 = pattern13.Matches(input);
                    for (int tempNumber34 = 0; tempNumber34 < patternMatches9.Count; tempNumber34++)
                    {
                        object obj9 = null;
                        if ((tempNumber6 < this.ClassTeacherTags.Count) && (this.ClassTeacherTags.Count > 0))
                        {
                            obj9 = this.ClassTeacherTags[tempNumber6].HashTableStudents[iD];
                        }
                        if (obj9 != null)
                        {
                            sbXMLString.Replace(patternMatches9[tempNumber34].Value, obj9.ToString().Trim());
                        }
                        else
                        {
                            sbXMLString.Replace(patternMatches9[tempNumber34].Value, " ");
                        }
                        tempNumber6++;
                    }
                }
                if (pattern20.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches10 = pattern19.Matches(input);
                    for (int tempNumber35 = 0; tempNumber35 < patternMatches10.Count; tempNumber35++)
                    {
                        string courseCode = string.Empty;
                        string courseName = string.Empty;
                        this.getCourseCodeAndName(patternMatches10[tempNumber35].Value, out courseCode, out courseName);
                        if ((courseCode != string.Empty) && (courseName != string.Empty))
                        {
                            PerfAttendanceTag attendance = null;
                            attendance = this.ClassesLateTags.GetAttendance(courseCode);
                            if (attendance != null)
                            {
                                sbXMLString.Replace(patternMatches10[tempNumber35].Value, attendance.GetAttendanceValue(student.PersonID));
                            }
                            else
                            {
                                sbXMLString.Replace(patternMatches10[tempNumber35].Value, "");
                            }
                        }
                        tempNumber7++;
                    }
                }
                if (pattern18.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches11 = pattern17.Matches(input);
                    for (int tempNumber36 = 0; tempNumber36 < patternMatches11.Count; tempNumber36++)
                    {
                        string tempStr15 = string.Empty;
                        string tempStr16 = string.Empty;
                        this.getCourseCodeAndName(patternMatches11[tempNumber36].Value, out tempStr15, out tempStr16);
                        if ((tempStr15 != string.Empty) && (tempStr16 != string.Empty))
                        {
                            PerfAttendanceTag tag2 = null;
                            tag2 = this.LessonMinutesLateTags.GetAttendance(tempStr15);
                            if (tag2 != null)
                            {
                                sbXMLString.Replace(patternMatches11[tempNumber36].Value, tag2.GetAttendanceValue(student.PersonID));
                            }
                            else
                            {
                                sbXMLString.Replace(patternMatches11[tempNumber36].Value, "");
                            }
                        }
                        tempNumber9++;
                    }
                }
                if (pattern16.IsMatch(tempStr4))
                {
                    MatchCollection patternMatches12 = pattern15.Matches(input);
                    for (int tempNumber37 = 0; tempNumber37 < patternMatches12.Count; tempNumber37++)
                    {
                        string tempStr17 = string.Empty;
                        string tempStr18 = string.Empty;
                        this.getCourseCodeAndName(patternMatches12[tempNumber37].Value, out tempStr17, out tempStr18);
                        if ((tempStr17 != string.Empty) && (tempStr18 != string.Empty))
                        {
                            PerfAttendanceTag tag3 = null;
                            tag3 = this.LessonAttendanceTags.GetAttendance(tempStr17);
                            if (tag3 != null)
                            {
                                sbXMLString.Replace(patternMatches12[tempNumber37].Value, tag3.GetAttendanceValue(student.PersonID));
                            }
                            else
                            {
                                sbXMLString.Replace(patternMatches12[tempNumber37].Value, "");
                            }
                        }
                        tempNumber8++;
                    }
                }
                MatchCollection patternMatches13 = pattern22.Matches(input);
                for (int k = 0; k < patternMatches13.Count; k++)
                {
                    if (this.StudentAchievementTags.Count > 0)
                    {
                        string newValue = "0";
                        PerfStudentBehaviour behaviour = null;
                        behaviour = this.StudentAchievementTags.GetBehaviour(PerfStudentBehaviour.TOTAL_ACHIEVEMENT_CODE);
                        if (behaviour != null)
                        {
                            newValue = behaviour.GetBehaviourPointValue(student.PersonID);
                        }
                        sbXMLString.Replace(patternMatches13[k].Value, newValue);
                    }
                }
                MatchCollection patternMatches14 = pattern21.Matches(input);
                for (int m = 0; m < patternMatches14.Count; m++)
                {
                    if (this.StudentBehaviourTags.Count > 0)
                    {
                        string behaviourPointValue = "0";
                        PerfStudentBehaviour behaviour2 = null;
                        behaviour2 = this.StudentBehaviourTags.GetBehaviour(PerfStudentBehaviour.TOTAL_BEHAVIOUR_CODE);
                        if (behaviour2 != null)
                        {
                            behaviourPointValue = behaviour2.GetBehaviourPointValue(student.PersonID);
                        }
                        sbXMLString.Replace(patternMatches14[m].Value, behaviourPointValue);
                    }
                }
            }
            if (input.Trim().Length > 0)
            {
                pageText = pageText.Replace(input, "").ToString().Trim();
            }
        }
    }
    this.moreThanOneTaginCell(sbXMLString);
}
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

http://thedailywtf.com/articles/shadow-over-xml


Метки:  

Error'd: Schr"odinger's Tortoise (SVN)

Пятница, 30 Октября 2015 г. 13:00 + в цитатник

"It's curious that SVN is simultaneously both clean and unclean until the computer is restarted," Hesham M. wrote.

"As one of the few people who still play Draw Something, I like it that they want to keep us occupied for a while," writes R.C.

"Apparently, the legalese in Microsoft's licensing terms is all French to Chrome...Sacrebleu!," wrote Martina O.

"True, names of pizzerias are all too often just overused Italian clich'es," Oton wrote, "but a 'Sample Text' pizzeria redefines originality!"

"That first option looks like it could be a good deal," writes Abe S., "if I'm staying in a castle."

"Firefox has a safety mechanism that lets you abort a script that's stopped working. In theory," Cal A. wrote.

Ryan T. writes, "I saw this today when I went to get some new passport photos from one of the automated photo booths. Needless to say I couldn't afford it!"

"Saw this while waiting for my mother's flight to arrive. Also...Access?" wrote Cheska C.

[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!

http://thedailywtf.com/articles/schr-dinger-s-tortoise-svn


Метки:  

CodeSOD: Leading Development

Четверг, 29 Октября 2015 г. 13:30 + в цитатник

H. J. works in a place where best practices are known, but bitterly opposed. You see, they have a lead developer who is more experienced than the rest, and it is his mission to show the others how things should best be done. Some of his finer resume-worthy accomplishments...

  • He removed salted hashes from the database and stores passwords in clear text
  • He swapped out the challenge-response mechanism and replaced it with sending clear text credentials in every request and reply
  • The data-access and object-persistence NHibernate layers were removed and raw db CRUD operations were exposed directly to the internet via these clear-text passwords
  • Set-operations (e.g.: delete-query) were replace with a select and then iteration over the resultant rows - each in its own session (race conditions, transactions: fuggedaboutem)
  • No keys or indices were used in db tables as NHibernate would handle it, even though many tables have more than a million rows
  • Mandatory helper classes log and swallow error and fatal exceptions, leaving them scrolling by on the lead dev's monitor, in case he has time to look at them (this way, the application keeps going and if anyone ever notices something didn't work correctly, they can go scrape the log files)
  • To simplify things, every class and interface had its own namespace and if possible, assembly
  • The build auto-increments the version number of all (changed) assemblies (e.g. just about every class) after each build and then commits it to SVN, pretty much guaranteeing merge issues
  • Created a utility to auto-insert "useful" comments for names of public classes, and name, type and parameters of public methods

This is one class, directly from version control, that deals with Visual Studio solutions and projects. SVN history says it has had precisely one change in it's nearly decade-long life: the addition of the auto-inserted comment:

using System;
using System.Collections.Generic;
using System.Text;

namespace CompanyName.Service.Common
{
 ///  public Class - Project_Helper
 public class Project_Helper
 {
 }
}

...and the code:

namespace CompanyName.Service.Common
{
 ///  public Class - Project_Helper
 public class Project_Helper
 {
 }
}
[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an impressively-featured free edition, too!

http://thedailywtf.com/articles/leading-development


Метки:  

Tales from the Interview: Monitoring the Situation

Среда, 28 Октября 2015 г. 13:30 + в цитатник

Joe T recently decided it was time to go job hunting. This mostly meant deflecting emails from head-hunters, doing phone interviews with ignorant HR departments, and the occasional on-site interview with a possible employer. One of those on-site interviews brought him to an IT services company which handled a few large US government contracts.

004. Brasserie La Saint-Pierre `a Saint-Pierre (Bas-Rhin)

The building itself was buried way in the back of a tech park, behind a small pond inhabited by ducks and migrating geese. It was modern, in a circa 2002 way, gleaming white, with a large and mostly empty parking lot, and a glossy lobby and a pair of cheerful receptionists.

One of the receptionists made a call. A few moments later, Ricky, Joes contact, stumbled out of the elevator. He had the look of a man who hadnt slept in a month. As they piled into the elevator, he said, We are really eager to fill this position. Just between you and me, I think youve got it sewn up, but you need to meet the team.

Ricky led him into a conference room, where a few other sleep-deprived looking techs nursed their coffees. After a round of handshakes, they dove into a series of sysadmin/operations questions. Some of them were just dumb trivia: Whats the purpose of the -i flag on the ls command? Some were dumb soft-balls: What time management techniques do you use?

After the warmup, Ricky leaned forward, and got right to the meat of it. Youve got three data centers, he said, how would you monitor all three of them?

That was a vague question, so Joe could only give a vague reply. Well, Id imagine all three are connected to the same management network. So Id run some sort of monitoring package on that network.

You dont have that, Ricky said. Joe couldnt be sure, but he thought he might have seen a grimace on the face of one of the techs.

Well, Joe said, then wed just have to set up monitoring in each DC independently, and then aggregate somehow, but thats really not the best option. Setting up a management network is-

Ah, Ricky interrupted, but what if you dont have the budget for any monitoring software?

Joe, sitting in the middle of the interview, jumped to a conclusion about Rickys line of questioning. This was one of those old interview tactics: no matter how the candidate replies, throw up an obstacle, and see how they can think outside the box. This was just a bizarre hypothetical situation. He played along. I guess wed need to install Nagios or some other open source monitoring tool.

The customer doesnt allow any open source software on the network, Ricky countered.

None? Joe asked. But dont you have some Linux servers?

Ricky nodded. We do. But no open source software on the network.

Well, I mean, if you cant buy software, and you cant use free software, you cant really do any meaningful monitoring.

Now Joe was certain: the techs were all grimacing, and oh so very slightly nodding along with him. This was what they expected him to say, but Ricky wasnt going to give in yet. Now, you cant just throw your hands up and say, It cant be done. You have to monitor these datacenters, so what do you do?

Well… I mean, at that point, were just writing our own scripts and running cron jobs. But thats a totally ridiculous scenario. No one would actually run a datacenter that way! Joe punctuated the statement with a laugh, because obviously this was all just silly.

No one else laughed. Rickys line of questioning wasnt a hypothetical, it was an accurate description of their infrastructure in their datacenters. After a solid minute of awkward silence, Ricky started asking questions about the previous jobs on Joes resume.

Somehow, Joe left the interview with a job offer, but he politely declined.

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

http://thedailywtf.com/articles/monitoring-the-situation


Метки:  

CodeSOD: The Hard Problem

Вторник, 27 Октября 2015 г. 13:30 + в цитатник

Ill warn you to start: this is a date handling CodeSOD, but thats only a small part of the WTF. You see, theres an old joke, There are three hard problems in computer science: naming things and counting things. This code has a hard time with the first:

       private string ReturnCurrentGMTTime()
        {
            string result = string.Empty;
            DateTime time = DateTime.Now;
            string fs = "yyyy-MM-dd'T'HH:mm:ss";
            result = time.ToString(fs);
            result += "+02:00";
            return result;
        }

Robert sent this in, after receiving it from a contractor.

This method name is a thing of beauty, simply because it is so wrong. Everything about it is wrong. The first problem is small, but rarely do we use the word Return as part of a method name. GetCurrentGMTTime would be better, but as this is C#, the convention is just to treat it like a property: CurrentGMTTime. Of course, GMT stands for Greenwich Mean Time, so like ATM Machine, our method name remains wrong. Perhaps it should be CurrentGMT or CurrentGMTime.

But thats small potatoes. Not only is the method just poorly named, its wildly inaccurate. DateTime.now only returns GMT in the event that you are on a machine in that time zone- which I happen to know that Robert is not. Hes actually in Denmark- which explains the +02:00- during Daylight Savings Time, that is their offset from GMT.

So, the method isnt ReturnCurrentGMTTime, but it is CurrentTimeWithTimeZone. And, of course, this formatting uses some of the built-in formatting functionality from .NET, but decides in the end to use string concatenation to take it the last mile. In the end, it's not wrong- just stupid.

[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!

http://thedailywtf.com/articles/the-hard-problem


Метки:  

Just Following Instructions

Понедельник, 26 Октября 2015 г. 13:30 + в цитатник

Cameron was a support rep for a Unix-based software package that had also been ported to Windows and Mac OS X. He supported every version, and quickly learned that not all ports were created equal.

Click Here. No, Here

The Windows port was the angel of the pair. The developers had written an installer with NSIS that created an icon on the Desktop for users to double-click. It worked well enough that Cameron almost never fielded Windows install support tickets.

The Mac port was the devil from a support standpoint, and there was really no good reason for it. As long as Xcode and X11 were installed on the user's machine, everything worked perfectly. However, few Mac users had these libraries out of the box.

No problem. On their product download webpage, they supplied links not just to their own installer, but also for the Xcode and X11 installers. And yet, the number of users calling in to flail helplessly were numerous.

"What link? I don't see it anywhere!"

"The installer's on another site?"

"What do I do now?"

When Cameron walked users through the process verbally, it always went fine. He got so much practice at it that the instructions were practically encoded into his neurons.

One day, Cameron had a sanity-preserving idea. He ran it past his boss, who then set up a meeting with the product website masters.

"We field a ton of calls for this Xcode and X11 install stuff," Cameron explained. "No one can figure it out without some help. I'd like to set up a webpage describing the whole install process step-by-step. I think it'll really cut down on the confusion. I know HTML, I can put the page together myself with screenshots and everything."

Everyone agreed it was a good idea. After some minor negotiating, the web team agreed to give Cameron access to the product website's test domain. "Write up the page you want. Once you get it how you want it, we'll QA it, then promote it," they told him.

The opportunity to do something outside the same old support work was exciting to Cameron. His HTML experience came from all the personal websites he'd thrown together since the days of Geocities, and wasn't too shabby. He put together a nice step-by-step breakdown, describing every detail of going to the appropriate external website and running the installers, with screenshots and links to everything the users would need. In the screenshots, he painstakingly indicated each button and link to click with little circles and arrows.

His boss liked the page, praising his "moron-proof," thorough instructions. The page went live soon after. Cameron looked forward to spending more time on more challenging support tasks.

A few months later, he resigned himself to the bitter reality that nothing had changed. It seemed no one on the planet could perform the Mac install unassisted. He fielded calls from end users all the way up to "network administrators" and "tech professionals."

"It doesn't work for me! Nothing happens when I click the links!"

"I followed your instructions to the letter, but the icons didn't work."

"Nothing happened."

Strangely, each time Cameron walked someone through the process, everything went fine. He couldn't understand it.

Neither could his boss, who wanted to reduce this pain point for his support staff. He approached Cameron one day with a suggestion. "Hey, we're doing a trial of this new remote viewing tool. It'll let us see exactly what users are doing, and dig into their systems directly if we have to. Would you like to try using it to see what the deal is with these Mac installs?"

"Sure!" Cameron was willing to try anything.

It didn't take long for another call to test on. "When I click the icon, nothing happens," the user explained to Cameron.

"All right." Annoying, but old hat by that point. "I'm gonna email you a link to a remote viewing session. This'll let me watch your install process. Can you click that link when you get it?"

"Sure."

They were connected a few moments later. The man's kitten-festooned desktop filled Cameron's view.

"OK, can you go to your browser and walk me through what you're trying to do?" Cameron asked.

"OK." The user opened up a new browser window and clicked a bookmark in the toolbar. "First, I go to your product page."

It loaded obediently a few moments later.

"I go to the instruction page …" He clicked the link to Cameron's how-to page. "Scroll down here a bit … then I click this icon, and nothing happens."

Cameron looked on in mute horror as the user furiously clicked a screenshot displaying the X11 icon with a circle around it. The 3x3-inch screenshot that he'd been careful to label "Screen Shot" in big letters.

"Oh. Uh …" Are you kidding me? This is what everyone's doing?! Cameron took a deep, calming breath before continuing. "That's not where you want to be clicking. Just a little higher than that is a link that says ‘Click here to open the Xcode install page in a new window.' Can you try that one?"

"OK." The user complied, and the Xcode site loaded obediently.

"There we go!"

Cameron had no trouble walking the user through the rest of the process. Afterward, he sat back with a frown, thinking. Should he remove the screenshots? No, they were important for illustrating what to do on the Xcode and X11 websites. There was a better way to handle this, he was certain.

He took to Google. After a little research on Javascript onclick events, he contacted the web maintenance team, describing the change he wanted to make.

Sure! they emailed back. Do it in test and tell us when you're done.

From there, Cameron added a script to his webpage so that whenever someone clicked on any screenshot, a window popped up that read, "You are clicking on a screenshot within our instructions. In the Xcode/X11 website, find the window that resembles the screenshot and click on the icon there."

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

http://thedailywtf.com/articles/just-following-instructions


Метки:  

Error'd: Google's Time Travel Shenanigans

Пятница, 23 Октября 2015 г. 13:00 + в цитатник

"10 minutes is pretty reasonable, but I don't think that I'm going to make my connection 2 minutes in the past," writes Rich H.

...and if you liked that one...

Hereward M. wrote, "I've found a magical time travelling embankment! Thanks, Google!"

"I have no idea what the question is even asking," wrote Adam F., "I mean, practicing what, piano?"

"I don't know if I'd say that setup is blocked. I'd say an impasse is more like it," Bj"orn F. writes.

"After trying three times, I give up. FINE. Turn off podcast syncing," writes Scott S.

Peter G. wrote, "An operation failed, and there was a reason for it. That is all."

Ammar writes, "Sure, it says not to localize, but really, someone probably should have."

"Wow. I didn't realise my SQL database had got so big, maybe it's time to move it into the cloud?" wrote Mack.

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

http://thedailywtf.com/articles/google-s-time-travel-shenanigans


Метки:  

CodeSOD: A Well Mapped Error

Четверг, 22 Октября 2015 г. 13:30 + в цитатник

Marvins company had a problem. Their C++ application tended to throw out a lot of error codes. That was actually okay- that application had a lot of possible failure modes that it couldnt do anything about other than cough up an error and quit.

The problem was that their customers werent particularly happy with messages like: Error: QB57, since it told them absolutely nothing. RTFM was not an acceptable response, so someone had to add some functionality to turn those cryptic error codes into meaningful messages.

Since it was a simple job, they handed it off to the co-worker who nobody really thought all that much of. He was a terrible programmer, but how badly could he screw a simple map/hash/dictionary problem up?

First, construct the data structures to hold the error messages:

ERROR_REC Error_A_List[] = {
  {"AA01", "Error AA01 Description"},
  {"AA02", "Error AA02 Description"},
  /* about 100 more! */
};
ERROR_REC Error_B_List[] = 
{
  {"BA01", "Error BA01 Description"},
 {"BA02", "Error BA02 Description"},
/* more of course */
}
/* etc for all the letters! - 26 total 2D arrays*/

Well, thats a bad start. Two-Dimensional arrays arent the best way to represent a map, but hey, maybe they have a clever way of searching them?

const char* GetErrorDescription(char *wk_code) {
  bool done = false;
  int indx = 0, _wk_arr_size = 0;
  memset((char*) ret_desc, 0, 400);
        
  switch(wk_code[0]) {
    case 'A': _wk_arr_size = sizeof(Error_A_List)/sizeof(ERROR_REC);    break;
    case 'B':  _wk_arr_size = sizeof(Error_B_List)/sizeof(ERROR_REC);   break;
/* etc for C through Z - who doesn't love a 26-option case statement? */
}

  ERROR_REC *wk_Error_List = new ERROR_REC[_wk_arr_size];
  delete [] wk_Error_List;

  switch(wk_code[0]) {
    case 'A': wk_Error_List = Error_A_List; break;
    case 'B': wk_Error_List = Error_B_List; break;
/* Second verse, same as the first…*/
  }

  while (!done) {
    if (strcmp(wk_code, wk_Error_List[indx].Code) == 0) {
      done = true;
      strcpy(ret_desc, wk_Error_List[indx].Desc);
    }
    indx++;
    if (indx >= _wk_arr_size)
      done = true;
    else {
      if (strcmp(wk_code, wk_ResultCode_List[indx].Code) < 0)
        done = true;
      }
  }
  return ret_desc;
}

… I guess not. Not only do we have a total of 62 branches worth of case statements, but we have a first-year CS majors solution to breaking out of a while loop. A loop that just brute forces its way through the list of possible codes.

The best thing we can say is that the code has been optimized- never will it need to brute-force its way through every possible error code. Instead, it brute-forces its way through approximately 1/26th of them.

Marvin said, I was going to replace it with about 5 lines of code, but I think Ill get more enjoyment by leaving it the way it is. From this, I assume Marvin is a horrible person, or his company uses lines-of-code as a productivity metric.

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

http://thedailywtf.com/articles/a-well-mapped-error


Метки:  

Apache Chief

Среда, 21 Октября 2015 г. 13:30 + в цитатник
W.T.F. Community College hired a team of highly-recommended web design consultants to bring its website in to the 21st century. Paul was tasked with overseeing their work and supporting the new site upon go-live. After a couple months of grinding, they cranked out a beautiful new site that was accessible, navigable, and responsive. It also removed the old site's dependence on Flash, replacing it with a titanic mound of PHP and JavaScript that was run by Apache.

Paul and his team gave it a thorough beating in their test environment and everything seemed solid. They even gave a demo of it to the the head of W.T.F. Community College, President Skroob. He was able to easily find his way around, sign up, set his password to 1-2-3-4-5, and register for fake classes. It got the Prez's official salute of approval. The amazing new website was ready to be launched in time for the fall semester.

The first day of classes rolled around and suddenly everything didn't seem so rosy. President Skroob frantically burst in to the IT office shouting "The web site is down! The web site is down!" A quick check of the monitoring system didn't show anything wrong, and manual inspection didn't either. The server hosting the site was hardly breaking a sweat. No pressure on CPU, RAM, or I/O. Paul tried browsing to the site and the browser just hung. No errors, no nothing.

"Well that's interesting," Paul said to no one in particular. "We've lost the bleeps, the sweeps, and the creeps."

"Why don't we try restarting Apache?" one of Paul's cohorts suggested. Paul shrugged and did so, and the website immediately returned to normal.

"I don't know what old Indian tribes have to do with our web site, but I'm glad it's working now!" President Skroob stated before ducking out of the office.

Paul set up a simple monitor to hit the home page every 5 minutes to make sure the problem didn't return. But an hour later, the alarm went off. He restarted Apache quickly, and things cleared up. So began a nightmare where someone from Paul's team always had to be available to restart Apache once the website hung. The Prez was not pleased.

"Get a hold of the Apache Chief who made this website and get them in here to fix it NOW!" Skroob shouted at Paul.

Paul got on the horn to the consultants, who hemmed and hawed about checking their code. If they were to be brought back in, it would cost W.T.F. CC an exorbitant sum. Paul decided to look more closely at the server first, and found Apache was running out of processes. He increased the MaxProcesses limit which bought them some time before the site would hang again. All processes were stuck in CLOSE_WAIT status, meaning the client browser had closed the connection but the server hadn't.

A system call trace on a stuck server process showed it was waiting on a file lock, and a stack dump showed the culprit was `mod_php`. Since they were waiting on a lock, they were suspended and couldn't exit. In fact, all the dozens of stuck processes were waiting on the same file: `/var/lib/php/session/sess_111`.

Paul got back on the phone with the consultant team and learned the story behind this big WTF. The new website had feeds (such as current events and the faculty directory) that could be updated dynamically and might be accessed from any session. But to avoid regenerating the output HTML on each load, it was cached so every PHP process could get to it. The consultants had done this using a single, global, monster PHP session.

Thus, every website hit required a server process to read and write that one session, thus locking the session file. If new requests came in at Ludicrous Speed, they were unable to get through the bottleneck and eventually Apache couldn't spawn any more processes. At that point, the site would go catatonic to the user.

"Guys, this is in no way acceptable," Paul berated Apache Chief & Co. "You need to find another approach to caching the data." Meanwhile, Paul wrote a workaround script that ran once a minute and restarted Apache if there were too many stuck processes. Two weeks and thousands of dollars later, the consultants ameliorated the problem by dividing traffic amongst four different cache "sessions".

It worked well enough that Paul's script only got triggered during extremely high usage times. Even then, there was very little downtime. President Skroob put the kibosh on any more of the school's Space Bucks going to the Apache tribe, so getting them to develop something that wasn't just a hack job was out of the question. As long as it worked most of the time and kept Skroob out of their office, Paul was comfortable with leaving well-enough alone.

[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an impressively-featured free edition, too!

http://thedailywtf.com/articles/apache-chief


Метки:  

CodeSOD: Sort, Then Add, Forever

Вторник, 20 Октября 2015 г. 13:30 + в цитатник

Go-live day for the new CabinetWorld redesign was a tense, hurried affair. Developers streamed in at 5:00 AM, hoping to catch wind of early problems before most of the country awoke and started shopping. True to form, the overworked break-room coffee machine gave up the ghost at 5:10, but luckily, at 6:00 the boss brought in doughnuts, and by 6:30 a Starbucks run had been arranged. Everyone huddled in the war room, nervously watching the monitors as the number of concurrent visitors rose steadily. And then ...

1890s Burroughs adding machine

"Why's it slowing?" Ashley whispered, not wanting to cause a panic.

Dave stuffed the rest of a cruller into his mouth and looked where she was pointing: one particular API service was buckling under the so-far moderate load. Oddly enough, this wasn't part of the overhaul. This service, which merely returned a product list, was a legacy service they'd switched to using, one that powered their own internal tools. It should've been nice and stable—but instead, it chugged along like it had eaten a few too many doughnuts itself.

Dave grabbed the source code while Ashley combed the production logs, looking for the source of the slowdown. "Crap," whispered Dave, noticing the version control history. "That's Bruce the Intern's work."

Bruce had been the "clever" intern the summer he'd worked at CabinetWorld, the one they'd assigned actual coding tasks to. Unfortunately, he'd been too clever for his own good, as the code revealed:


public List getAllCabinets() {
	try {
		List m = new Vector();
		List cabinets = SpecificObjectManager.getAllPrograms();
		Iterator it = cabinets.iterator();
		while (it.hasNext()) {
			CabinetAjax ca = new CabinetAjax();
			SearchProgramShell cabinet = (SearchProgramShell) it.next();
			ca.setId(cabinet.getCabinetId());
			ca.setTitle(cabinet.getCabinetTitle());
			Collections.sort(m, new CabinetAjaxTitleComparator());
			m.add(ca);
		}
		return m;
	} catch (Exception e) {
		log.error(e.toString(), e);
	} finally {
		HibernateSessionFactory.closeSession();
	}
	return null;
}

"That is, without a doubt, the worst sort I've ever seen," whispered Ashley, paling. "Why does it re-sort every iteration?"

"It doesn't even work. The last element won't be sorted," Dave whispered back.

"Why a vector of CabinetAjaxes? Why not just a Map, ID to title?"

"God only knows."

"What do we do now?" Ashley glanced up at the increasingly red monitors. "Do we roll back?"

Dave clamped a hand over her mouth. "Not so loud! No. We write a patch and fail forward, of course." He rapidly moved the sort code to just before the return, saved, and committed. "Let's see if we can bribe Ops with some of these donuts ..."

[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an impressively-featured free edition, too!

http://thedailywtf.com/articles/sort-then-add-forever


Метки:  

An Efficient Curmudgeon

Понедельник, 19 Октября 2015 г. 13:30 + в цитатник

One of the things a good developer should always strive for is efficiency. Slow code should be improved if possible. Complicated steps should be simplified or removed. Finding a poorly-implemented process which is costing company time and streamlining it is usually a good thing, and means more profits, which means larger paychecks and bonuses, and happy bosses. Right?

The ASS Automation System's corporate headquarters.
This is a real company, but not where our story comes from

Dave had been working in the shipping department for a while when he discovered how the monthly shipping statistics were gathered. His coworker, Clarke, walked him through the process one day when Dave had some downtime.

Everything comes in as Excel reports from our two software systems, Clarke began. Then I have to edit them to get them in the same format, combine them, and muck around with filters and sums to get the numbers the boss likes to see.

Dave shuddered at the thought of manually hacking reports together. How long does it take you?

Its not too bad anymore, maybe four or five hours. Sometimetimes longer if I make a mistake. Clarke shrugged. Its not hard, just tedious.

And this is each month?

Yep. It used to take me a few days until I got used to it.

Dave thought for a moment. The data isnt complicated at all. I bet I could write a script to do most of it for you.

Clarkes eyes lit up at the suggestion. Really?

Together they went to their supervisor, an older gentleman named Rick who looked like he could retire any minute now. After a brief proposal, Rick didnt seem impressed. The current system works fine, I dont think it needs to be changed.

I could have the whole thing written in less time than it takes Clarke to process one monthly report, said Dave. After that, all hed have to do is click a button. Were talking minutes instead of hours.

Rick muttered something and dismissed them. Dave and Clarke left, unsure if they had permission to proceed.

Dave wrote the new system anyway. Once hed received some older reports to understand the formatting, he spent a few hours of spare time to write up a fairly simple C# program to automate all the manual editing that Clarke had to do. With a long history of previous reports and the historical data, Dave proved the programs accuracy by running it across a years worth of data.

It worked flawlessly. Creating the monthly report now only took about ten minutes, most of which was spent waiting on connections to the other software systems. Once it had all the data, it spit out the report in less than a second. When the next report was due, they generated it using Daves application and avoided hours and hours of Excel wrangling.

Rick was not impressed when they showed him their work. How do I know if its right? he asked. I dont really trust computers. Ill have to verify everything myself now!

And that he did. Rick spent the next two days printing out every daily-activity email for the previous month, calculating all the shipping statistics with a four-function calculator, and compiling results on a sheet of notebook paper. And because the emails were user-generated, not system-generated, they often contained minor errors which required even more time to correct. After several tries, Rick eventually had a report that agreed with Daves.

And this continued for a few more months. Daves program would generate an accurate report within minutes, then Rick would spend hours, if not days, hidden within a small fort made of printed emails, only to eventually come up with the same numbers.

Word got out on Daves accomplishment and he was soon offered a transfer to another department. The supervisor there was not afraid of modern technology and wanted to replace their current paper-based delivery manifest process with a computer-based solution that could save thousands of dollars in printing costs. Dave accepted the transfer and eagerly started on the new project. And last he heard, Rick had thrown away Daves little shipping report program and even the old Excel report system, instead dealing with stacks of printed emails and a four-function calculator to generate a handwritten report each month.

[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!

http://thedailywtf.com/articles/an-efficient-curmudgeon


Метки:  

Error'd: For Quality Assurance Purposes

Пятница, 16 Октября 2015 г. 13:00 + в цитатник

"I don't work for them, so when did it become my job to do their quality control?" writes T. K.

"You know, I'm pretty sure 100% of people with regular gigs have at least one of these fantasies," writes Tim R.

"This likely gives a clue to why workstations at my site are failing like a classroom of 6th-graders taking a college algebra exam," wrote Jonathan.

"Apparently the advanced paid-for features also includes labels for buttons," Robert S. writes.

Paramdeep wrote, "Text! Come here please!"

"A recent Error'd had a photo showing the source of Apple's Command keys in the Faroe Islands," Peter G. wrote, "This is a shot of a Norwegian Command center, located just outside Fredrikstad in southern Norway."

Magnus M. writes, "This came from a program used for interfacing with a medical microscope. Serious stuff, no doubt. It seems like the main application would rather be at it alone."

"If by 'instant' you mean 'it will take upwards of 30 seconds', then yeah, it's 'instant', " wrote Jason.

[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!

http://thedailywtf.com/articles/for-quality-assurance-purposes


Метки:  

CodeSOD: Validate My Feelings of Cleverness

Четверг, 15 Октября 2015 г. 13:30 + в цитатник

Its not uncommon to have a branch in your code along the lines of, if (debugMode) { doSomeLogTypeThingy(); }. Usually, we try and wrap that sort of stuff up and keep it far away from the actual business logic, and the result is a plethora of logging frameworks and diagnostic libraries.

They are, however, consistent about one thing: whether or not debugMode is enabled or not, the actual business logic should behave the same way. Theyre designed and intended to be minimally disruptive.

Remco found this method:

       public static void objectIsValid(final Object objectToCheck, final String objectName) {
                if(objectToCheck instanceof Validatable){
                        objectIsValid((Validatable)objectToCheck, objectName);
                }else{
                        if(     log.isDebugEnabled() &&
                                objectToCheck != null &&
                                objectToCheck.getClass().getPackage().getName().startsWith("com.initrode") &&
                                !objectToCheck.getClass().getName().contains("Enum")
                                    ){
                                        throw new IllegalArgumentException("this class should implement validatable:"+objectToCheck.getClass());
                        }
                        validateObjectIsNotNull(objectToCheck, objectName);
                }
        }

This mess of code takes the interesting stance that, if debugging is enabled, that means it should throw exceptions, but if debug mode isnt enabled, it should just… not do anything?

Of course, thats not the only useless thing in that method. Note at the top, where they use instanceof to check if the object can be cast to a Validatable? And then it passes it to what is obviously an overloaded method that accepts a Validatable?

    public static void objectIsValid(final Validatable objectToCheck, final String objectName) {
                validateObjectIsNotNull(objectToCheck,objectName);

                ConstraintViolation[] invalidValues = validatorRepos.validate(objectToCheck);
                if(invalidValues.length > 0){
                        throw new ValidationException(invalidValues);
                }
        }

Yeah. So there is no planet in which the first branch would ever evaluate to true, and since debugging mode is nearly never enabled in production… well, at least they got to use reflection, I guess.

[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an impressively-featured free edition, too!

http://thedailywtf.com/articles/validate-my-feelings-of-cleverness


Метки:  

Filing Data

Среда, 14 Октября 2015 г. 13:30 + в цитатник

Databases are wonderful things. They help you organize your data at multiple levels. Large logical units of data are stored in databases. Smaller logical divisions are stored in tables, and individual records are stored in rows. Once you have your data stored like that, you can access it in all sorts of wonderful ways.

A filing cabinet

Of course, there's more to it than that. Beneath the database is the file system. Beneath that, there are one or more drive arrays each with one or more disk drives, each with one or more platters. Read/Write heads move back and forth to access the data on those platters. All sorts of sophisticated mechanisms have been developed to minimize the dead time of having a head in the right place, but waiting for the platter to spin the data beneath it for retrieval.

DBAs take this into account when defining where the database and included tables will be stored. For example, they shouldn't put two databases (for different applications) that require extremely high rates of access on the same disks so as to minimize contention, because a head can't be in two places at once. Sometimes, they'll stripe data for a single table across multiple spindles so as to minimize hot spot activity by hashing the data across partitions.

Mr. Anon. works with a DBA who believes that there is a better approach. Each database should contain one table. That database should reside in its own data file on the disk. Accordingly, there were thousands of data files. Since the operating system has a limit on the number of open file handles, the data server could only access so many databases at one time. The underlying theory was that this would reduce contention.

However, since the files are stored all over the disks, the heads-can't-be-in-two-places-at-once issue still causes problems. Since a table/database is stored in a single file, it's no longer possible to stripe it (as one might with partitions). Also, since the data server can only open so many file handles at once, in order to open more, it must juggle opening and closing database file handles. As one might expect, this overhead is substantially noticeable.

Of course, there is the maintenance side of things as well. Changing the log segment of a 200 table database is basically a one-off action. Doing it for a database that is stored as 200 separate databases of one table each now becomes a significant amount of effort. It's still O(n), where n is the number of databases, but now it's a huge effort. The same goes for every other database-level attribute.

A more interesting facet is that now it's possible for only one table of your database to go down while all the others are happily processing requests. Now you need to code multi-table inserts as multi-phase commits.

Equally interesting is how one might code a join of n tables, when it's possible that zero or more of them might be in databases that are unavailable. Hmm?

All of this was rationalized as acceptable because it was all to support a web application, where performance didn't matter.

Ah well, at least this way you know you'll never find a database with thousands of tables in it.

[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!

http://thedailywtf.com/articles/filing-data


Метки:  

Поиск сообщений в rss_thedaily_wtf
Страницы: 124 ... 30 29 [28] 27 26 ..
.. 1 Календарь