<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Should Have Paid Me More</title>
	<atom:link href="http://shouldhavepaidmemore.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://shouldhavepaidmemore.com</link>
	<description>Tales from the underpaid</description>
	<lastBuildDate>Sun, 29 Nov 2009 14:00:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The Utilization Report, Part Two</title>
		<link>http://shouldhavepaidmemore.com/2009/the-utilization-report-part-two/</link>
		<comments>http://shouldhavepaidmemore.com/2009/the-utilization-report-part-two/#comments</comments>
		<pubDate>Sun, 29 Nov 2009 14:00:20 +0000</pubDate>
		<dc:creator>spork</dc:creator>
				<category><![CDATA[Users]]></category>
		<category><![CDATA[inefficiency]]></category>
		<category><![CDATA[utilization]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=165</guid>
		<description><![CDATA["How does the utilization report arrive at its numbers?"

It seemed like a simple, straightforward and innocuous question at the time. Unfortunately, it opened an institution-sized metallic food storage container of blind, soil-ingesting invertebrates.]]></description>
			<content:encoded><![CDATA[<p><em>Note: You may wish to read </em><a title="The Utilization Report, Part One" href="http://shouldhavepaidmemore.com/2009/the-utilization-report/"><em>The Utilization Report</em></a><em> to gain context.</em></p>
<p>&#8220;How does the utilization report arrive at its numbers?&#8221;</p>
<p>It seemed like a simple, straightforward and innocuous question at the time. Unfortunately, it opened an institution-sized metallic food storage container of blind, soil-ingesting invertebrates.</p>
<p>You see, the person who&#8217;d commissioned the development of the utilization report didn&#8217;t really understand what he was building. He had vague amorphous ideas about what he wanted &#8211; perhaps he&#8217;d seen a report at some other company that was used to determine how well the employees were being utilized and decided it was a good idea. Based on second-hand knowledge and investigation into the reports themselves, here&#8217;s how I picture the utilization report&#8217;s progression in my head:<span id="more-165"></span></p>
<p><strong>Project Requester</strong>: &#8220;I want a report that tells me if there&#8217;s enough work for my employees.&#8221; <em>&#8211;note: He&#8217;s saying &#8220;show number of hours worked divided by number of hours that could have been worked&#8221;</em><br />
<em>&#8211; time passes &#8211;</em><br />
<strong>Programme</strong>r: &#8220;OK, here it is.&#8221;<br />
<strong>Project Requester</strong>: &#8220;It&#8217;s wrong. It needs to take holidays into account.&#8221;<br />
<em>&#8211; time passes &#8211;</em><br />
<strong>Programmer</strong>: &#8220;OK, here it is.&#8221;<br />
<strong>Project Requester</strong>: &#8220;It&#8217;s wrong. It needs to take PTO into account.&#8221;<br />
<em>&#8211; time passes &#8211;</em><br />
<strong>Programmer</strong>: &#8220;OK, here it is.&#8221;<br />
<strong>Project Requester</strong>: &#8220;It&#8217;s wrong. It  should use the number of hours the employee has been <em>scheduled</em> to work instead of the hours actually worked.&#8221;<br />
<strong>Programmer</strong>: &#8220;What?&#8221;<br />
<strong>Project Requester</strong>: &#8220;It has to.&#8221;<br />
<em><em>&#8211; time passes &#8211;<br />
</em><span style="font-style: normal;"><strong>Programmer</strong>: &#8220;OK, here it is.&#8221;<br />
</span><span style="font-style: normal;"><strong>Project Requester</strong>: &#8220;It&#8217;s wrong. If an employee had a job that ran late the night before, the Scheduling department schedules an employee for a block of time the next day in order to keep him from having to work. The report has to take that into account when it happens.&#8221;<br />
</span>&#8211; time passes &#8211;<br />
<strong><span style="font-style: normal;">Programmer</span></strong><span style="font-style: normal;">: &#8220;OK, here it is.&#8221;<br />
</span><strong><span style="font-style: normal;">Project Requester</span></strong><span style="font-style: normal;">: &#8220;It&#8217;s wrong. It needs to show that an employee worked the whole weekend if he was scheduled for a Saturday.&#8221;<br />
&#8211; time passes &#8211;<br />
<em><strong><span style="font-style: normal;">Programmer</span></strong><span style="font-style: normal;">: &#8220;OK, here it is.&#8221;<br />
<em><strong><span style="font-style: normal;">Project Requester</span></strong><span style="font-style: normal;">: &#8220;It&#8217;s wrong. It needs to assume every employee spent two hours to get to the job site and two hours to get home.&#8221;<br />
<em>&#8211; time passes &#8211;</em></span></em></span></em></span></em><br />
<strong>Programmer</strong>: &#8220;OK, here it is.&#8221;<br />
<strong>Project Requester</strong>: &#8220;It&#8217;s wrong.&#8221;<br />
<strong>Programmer</strong>: &#8220;How is it wrong?&#8221;<br />
<strong>Project Requester</strong>: &#8220;The numbers can&#8217;t possibly be that low. The report is wrong.&#8221; <em>&#8211;note: It showed an average of 64% utilization (i.e. employees jacked off 36% of the time for which they were paid). It was later found that actual utilization was 52% if they were afforded every possible benefit of the doubt.</em></p>
<p>The utilization report was used to determine year-end monetary bonuses for managers. However, every time the utilization numbers were too low to allow the maximum bonus, the managers would say &#8220;The report&#8217;s always been inaccurate. The numbers are really much higher.&#8221; And the bonus would be awarded.</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/the-utilization-report-part-two/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Utilization Report</title>
		<link>http://shouldhavepaidmemore.com/2009/the-utilization-report/</link>
		<comments>http://shouldhavepaidmemore.com/2009/the-utilization-report/#comments</comments>
		<pubDate>Sat, 28 Nov 2009 18:03:00 +0000</pubDate>
		<dc:creator>spork</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[inefficiency]]></category>
		<category><![CDATA[MS Access]]></category>
		<category><![CDATA[utilization]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=161</guid>
		<description><![CDATA[A utilization report is essentially a view of hours worked vs hours paid &#8211; simple, right? You can determine appropriate staffing levels by understanding how much work they&#8217;re performing and how much work needs to be performed.
It turned out &#8220;the utilization report&#8221; at my company actually meant six distinct reports. Here&#8217;s how the system worked:

At [...]]]></description>
			<content:encoded><![CDATA[<p>A utilization report is essentially a view of hours worked vs hours paid &#8211; simple, right? You can determine appropriate staffing levels by understanding how much work they&#8217;re performing and how much work needs to be performed.</p>
<p>It turned out &#8220;the utilization report&#8221; at my company actually meant six distinct reports. Here&#8217;s how the system worked:</p>
<ul>
<li>At the beginning of every month, a user would submit an IT ticket as a reminder to &#8220;run&#8221; the report on the 15th of the next month</li>
<li>Somewhere near the 15th of the month, a specific developer would navigate to a directory on his machine and double-click an Access database</li>
<li>The developer would then locate each of the six reports in the Access database and run them all in turn, exporting them as RTF files when they finished</li>
<li>Each report was extremely resource-intensive and completely took over the IT guy&#8217;s computer, rendering him useless for hours &#8211; and even longer if the Access database crashed</li>
<li>When all reports had been exported, they were attached to an email and sent to the user from Step 1</li>
</ul>
<p><span id="more-161"></span></p>
<p>This process was repeated every month and caused much frustration for the user (because they couldn&#8217;t get the report immediately) and the developer (because it consumed his computer and he couldn&#8217;t get anything done). After hearing the developer curse and complain about the utilization report a few times, I set to work on the Access database. The process was changed to:</p>
<ul>
<li>On the 15th of every month, Windows Task Scheduler opens the Access database, triggering a VBA subroutine</li>
<li>Each report is exported to RTF</li>
<li>All exported reports are programmatically attached to an email message and sent to the user</li>
</ul>
<p>The new process is entirely automated and takes about three minutes to complete. It turns out Access was running all of the report queries (a bunch of UNION ALLs in a number of views) twice &#8211; once to display the report to the developer, and again to export the data to RTF. In addition, the formatting process required to display the report inside Access took an enormous amount of time, whereas the formatting of the RTF to be displayed in an external viewer was far quicker.</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/the-utilization-report/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Do Not Click Button</title>
		<link>http://shouldhavepaidmemore.com/2009/the-do-not-click-button/</link>
		<comments>http://shouldhavepaidmemore.com/2009/the-do-not-click-button/#comments</comments>
		<pubDate>Sun, 08 Nov 2009 19:15:03 +0000</pubDate>
		<dc:creator>spork</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Users]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=151</guid>
		<description><![CDATA[It seemed only fitting to provide them with the one thing they couldn't screw up: the Do Not Click button.]]></description>
			<content:encoded><![CDATA[<p>Everyone&#8217;s seen at least one enormous red button with a label like &#8220;GLOBAL THERMONUCLEAR WAR INITIATOR VALVE &#8211; DO NOT PUSH!&#8221;, oui? Of course there&#8217;s always a villain around to press the button and ostensibly end the world, but the general concept prevails.</p>
<p>Given the tendency of Plus users to do the most illogical things possible while refusing to read or apply any kind of instructions given and then blame the software for behaving &#8220;unexpectedly&#8221;, it seemed only fitting to provide them with the one thing they couldn&#8217;t screw up: the Do Not Click button.<span id="more-151"></span></p>
<p>A lot of thought went into the Do Not Click button. Its placement was particularly important &#8211; it had to be accessible yet unobtrusive enough to go unnoticed for a while. The button itself had to be recognizable as capable of performing an action, yet simple enough to be overlooked by a casual glance. It had to display enough of a warning to be clear that clicking was ill-advised, yet low-key enough to beckon seductively. The final product is thus:</p>
<p><a rel="attachment wp-att-152" href="http://shouldhavepaidmemore.com/2009/the-do-not-click-button/donotclick/"><img class="aligncenter size-full wp-image-152" title="The Do Not Click Button" src="http://shouldhavepaidmemore.com/wp-content/uploads/2009/11/donotclick.png" alt="The Do Not Click Button" width="123" height="33" /></a>Fetching, no? It was placed at the very bottom of the About dialog, which I doubt anyone ever accesses unless by accident. If any one of the 150 users happens upon it, however, he&#8217;s all but guaranteed to email the other 149 to tell them about it. And <em>that&#8217;s</em> when the fun starts.</p>
<p>&#8220;What happens when the Do Not Click button is clicked?&#8221; one might ask curiously. Let me give you the most likely scenario:</p>
<blockquote><p><strong>User</strong>: &#8220;What&#8217;s this thing that looks like a stop sign with a white X in it? That looks weird. Wait, there are some hieroglyphs beside it&#8230;they say &#8216;d&#8217;&#8230;no, &#8216;D&#8217;&#8230;I&#8217;ve got it! It says &#8216;Do&#8217;! Phew, that was hard work. I&#8217;d better take a break so as not to strain myself.&#8221;</p>
<p>&lt;- four hours later -&gt;</p>
<p><strong>User</strong>: &#8220;Why is there a window that says &#8216;About&#8217; open? This stupid software, always doing things I don&#8217;t tell it to! I&#8217;m going to create a helpdesk ticket for IT to fix it! No, I should compose a poison-filled email about how crappy Plus is and how it&#8217;s always broken and send it to all of the other field technicians so they can join me in my uninformed griping!&#8221;</p>
<p>&lt;- two hours later -&gt;</p>
<p><strong>User</strong>: &#8220;All that typing made me hungry. I&#8217;m going to go to the expensive steakhouse down the road and charge a hefty three-course to my company credit card and then take a nap.&#8221;</p>
<p>&lt;- the next day -&gt;</p>
<p><strong>User</strong>: &#8220;Hmm, what&#8217;s this window that says &#8216;About&#8217;? There&#8217;s a button that has a stop sign with a white X in it. It doesn&#8217;t say what it does&#8230;&lt;click&gt; Nothing happened. &lt;click&gt; &lt;click&gt; &lt;CLICK&gt; Stupid Plus! How can I be expected to perform any work if this trashy program won&#8217;t do anything? Those idiots in IT are just trying to keep me from doing my job!&#8221;</p></blockquote>
<p>Sadly, this is probably a realistic depiction of events. However, the Do Not Click button <em>does</em> do something &#8211; it records the number of times it&#8217;s been clicked. Yes, that&#8217;s right &#8211; there&#8217;s a persisted click count. When the user submits work (which is supposed to happen once every few days), the cumulative click count is stored to a server-side database along with the user&#8217;s username. There it waits until an intranet-accessible web page is requested, wherein it&#8217;s included in a report showing the users clicking the Do Not Click button the most.</p>
<p>And here&#8217;s the best part: Any &#8220;bug&#8221; report about the Do Not Click button being broken can be closed with &#8220;The button works as intended. Do not click the Do Not Click button.&#8221; When the question of why the button exists comes up, the answer is &#8220;The button is there to keep an issue from occurring. When the button is clicked, the issue occurs. If the button is not clicked, the issue does not occur. This is why it says &#8216;Do Not Click&#8217; on the button.&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/the-do-not-click-button/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Change It Back!</title>
		<link>http://shouldhavepaidmemore.com/2009/change-it-back/</link>
		<comments>http://shouldhavepaidmemore.com/2009/change-it-back/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 18:13:14 +0000</pubDate>
		<dc:creator>spork</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Users]]></category>
		<category><![CDATA[coworkers]]></category>
		<category><![CDATA[plus]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=142</guid>
		<description><![CDATA[He blamed me for "making changes without [his] knowledge".]]></description>
			<content:encoded><![CDATA[<p>Code comment written less than a month ago:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #008000; font-style: italic; font-weight: bold;">/**
 * Added 10/7/2009 by specific request of sjohnson. Of course there's no HD
 * ticket or other documentation for the request because everyone knows
 * normal rules don't apply to the field staff.
 */</span></pre></div></div>

<p>Code comment written today:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #008000; font-style: italic; font-weight: bold;">/**
 * Removed 11/5/2009 by specific request of sjohnson. Of course there's no HD ticket
 * or other documentation for the request because everyone knows normal rules don't apply
 * to the field staff. sjohnson swears this is a showstopper and must be removed because
 * now that he actually has to work in Plus on a daily basis he understands how
 * ridiculously foolish it is to clear out the time entry fields after every entry is
 * added to the table.
 */</span></pre></div></div>

<p><span id="more-142"></span>Mere days before a version of Plus was to be released, the manager in question demanded that the functionality be changed as it was &#8220;not the way the staff work&#8221;. He was made aware of the reason the product functioned the way it did and warned of the problems that would occur should his demand be met, but these logical beseechings fell upon deaf ears. He was given an opportunity (two full weeks) to test this change and he signed off on the final product. Almost exactly a month later, the manager had to take on the role of a field technician. As part of that, he had to use Plus, and blamed me for &#8220;making changes without [his] knowledge&#8221;.</p>
<p>This manager demanded that this and a second change be immediately coded and pushed into production as an &#8220;emergency&#8221; release&#8230;without any testing. He was warned of the expected problems of the second change and how testing helps ensure quality, but again he exhibited Deaf Man&#8217;s Vendetta. We&#8217;ll see how that turns out.</p>
<p><strong>Update</strong>: A week later (11/13/2009) the same manager went into another panic and demanded the functionality be reverted again, emailing &#8220;can you please verify and correct this issue immediately? This is the same issue we had in October!&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/change-it-back/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8216;Nuff Said</title>
		<link>http://shouldhavepaidmemore.com/2009/nuff-said/</link>
		<comments>http://shouldhavepaidmemore.com/2009/nuff-said/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 17:58:15 +0000</pubDate>
		<dc:creator>benson</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=137</guid>
		<description><![CDATA[.style1 { font-size: 10px;
font-family: Arial, Helvetica, sans-serif;
}
.style2 {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: medium;
color: #000066;
}
.style3 {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: x-small;
} .style17 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: medium; color: #BDFFFF; }
.style18 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: x-small; color: #FFFFFF; }
.style19 {color: #000066}
.style20 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: x-small; font-weight: bold; color: #000066; }
.style22 [...]]]></description>
			<content:encoded><![CDATA[<p><code>.style1 { font-size: 10px;<br />
font-family: Arial, Helvetica, sans-serif;<br />
}<br />
.style2 {<br />
font-family: Verdana, Arial, Helvetica, sans-serif;<br />
font-size: medium;<br />
color: #000066;<br />
}<br />
.style3 {<br />
font-family: Verdana, Arial, Helvetica, sans-serif;<br />
font-size: x-small;<br />
} <span id="more-137"></span>.style17 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: medium; color: #BDFFFF; }<br />
.style18 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: x-small; color: #FFFFFF; }<br />
.style19 {color: #000066}<br />
.style20 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: x-small; font-weight: bold; color: #000066; }<br />
.style22 {color: #000000}<br />
.style23 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: x-small; font-weight: bold; color: #000000; }<br />
.style24 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: x-small; font-weight: bold; color: #FF0000; }<br />
.style27 {color: #0000FF}<br />
.style29 {color: #0000FF; font-weight: bold; }<br />
.style30 {font-size: 8pt}<br />
.style31 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: x-small; font-weight: bold; color: #0000FF; }<br />
.style33 {font-size: small}<br />
.style34 {color: #FF0000}</code></p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/nuff-said/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>NULL Man</title>
		<link>http://shouldhavepaidmemore.com/2009/null-man/</link>
		<comments>http://shouldhavepaidmemore.com/2009/null-man/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 17:57:26 +0000</pubDate>
		<dc:creator>blaster</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NULL Man]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=108</guid>
		<description><![CDATA[I asked him why he decided to take this approach, and to my utter bemusement, his response was, "It's more efficient!"]]></description>
			<content:encoded><![CDATA[<p>I used to be a .NET Developer and DBA for an appliance manufacturer in a previous life.  The company was your basic good ole&#8217; boys shop where maintaining the status quo was priority number one.  It was such a staunchy work environment that you could determine where an employee was on the ladder based solely upon their attire.  High Level Execs wore full-out suits, with ties, vests, and sports jackets.  Your typical salaried employee generally just wore a button-up shirt and tie.  Shift managers wore polos, while the lowly hourly assembly workers donned jeans, steel-toe boots, and ratty shirts.  Basically, this manufacturing company is stuck in 1976 and doubled as my personal hell. <span id="more-108"></span></p>
<p>When I started working for this firm, they had an existing DBA who fancied himself a pretty smart guy.  Shy of the countless double-negatives and mis-information he would spew on a daily basis, he was tolerable and he kept to his world of existing &#8220;black magic&#8221; processes.  He liked to refer to himself as &#8220;NULL Man&#8221; and act like a super hero when he was &#8220;fixing bad data&#8221;.  For the first 9 months of my tenure, I really had no idea what he did on a day-to-day basis, but had a feeling his primary goal was to figure out how to interject himself into as many business critical processes as possible in order to assure job security.</p>
<p>I was hired to bring up new apps and databases and do some .NET development as well.  After about 9 months on the job, the Director of IT called me into his office and asked if I could rework a financial report he needed to give our CFO for the upcoming year-end.  In previous years, NULL Man would require a dedicated week&#8217;s worth of work to compile this report and massage the data to get the &#8220;proper numbers&#8221;.  This seemed like an awful amount of time to compile a 12 page financial report,  so our Director asked if I could take a look at it.</p>
<p>Leaving the Director&#8217;s office, I decided I would just go over to NULL Man&#8217;s desk and let him know that I was required to get cross-trained on how to create this report.  Under this guise, my plan was to basically dissect what in-fact was going on and automate it as much as possible so I didn&#8217;t have to deal with this again in the future, as developing reports never really excited me.</p>
<p>Thankfully NULL Man had a &#8220;busy&#8221; month-end coming up and welcomed the opportunity to &#8220;finally unload some of this work to someone else&#8221;.  We started out going over the purpose of this report and eventually how it all worked behind the scenes.  It turns out that this report wasn&#8217;t 12 pages by chance.  It was &#8220;designed&#8221; that way; each page having it&#8217;s own dedicated query to retrieve, cleanse, and format the data with Excel basically just acting as a container app.  The queries I were given were actually all stored procedures (to help with performance, of course) and were on average about 500 &#8211; 800 lines of code.  At first glance, this report looked very complex until I began to dig in and see what was actually involved.</p>
<p>It didn&#8217;t take more than 5 minutes to determine the real reason for so many lines of code.  NULL Man in his infinite wisdom wasn&#8217;t really fond of set operations, or really any advantages a database gives you when storing data in it, and he was even more clueless when it came to Excel.  Sadly, the query for each page would look something like this:</p>
<pre><span style="color: #008000">-- Get Information for Page 1
</span><span style="color: #0000ff">SELECT </span>Product, SubProduct, Cost, 0 <span style="color: #0000ff">AS </span>NewCol01
<span style="color: #0000ff">INTO</span> #tempTable1
<span style="color: #0000ff">FROM</span> SourceTable
<span style="color: #0000ff">WHERE</span> Product <span style="color: #808080">LIKE </span><span style="color: #ff0000">'%ProductLine1%'
</span>
<span style="color: #008000">-- Pull out information for Sub Product Line 1</span>
<span style="color: #0000ff">UPDATE</span> #tempTable1
<span style="color: #0000ff">SET</span> NewCol01 = Cost
<span style="color: #0000ff">WHERE</span> SubProduct <span style="color: #808080">LIKE</span> <span style="color: #ff0000">'%SubProductLine1%'</span>

<span style="color: #008000">-- Create a new Column</span>
<span style="color: #0000ff">SELECT</span> *, 0 <span style="color: #0000ff">AS</span> NewCol02
<span style="color: #0000ff">INTO</span> #tempTable2
<span style="color: #0000ff">FROM</span> #tempTable1

<span style="color: #008000">-- Pull out information for Sub Product Line 2</span>
<span style="color: #0000ff">UPDATE</span> #tempTable2
<span style="color: #0000ff">SET</span> NewCol02 = Cost
<span style="color: #0000ff">WHERE</span> SubProduct <span style="color: #808080">LIKE</span> <span style="color: #ff0000">'%SubProductLine2%'</span>

...

<span style="color: #008000">-- Create a new Column</span>
<span style="color: #0000ff">SELECT</span> *, 0 <span style="color: #0000ff">AS</span> NewColX
<span style="color: #0000ff">INTO</span> #tempTableX
<span style="color: #0000ff">FROM</span> #tempTableX-1

<span style="color: #008000">-- Pull out information for Sub Product Line X</span>
<span style="color: #0000ff">UPDATE</span> #tempTableX
<span style="color: #0000ff">SET</span> NewColX = Cost
<span style="color: #0000ff">WHERE</span> SubProduct <span style="color: #808080">LIKE</span> <span style="color: #ff0000">'%SubProductLineX%'</span>

<span style="color: #008000">-- Return Page 1 Information</span>
<span style="color: #0000ff">SELECT</span> Product, SubProduct, Cost,
    NewCol01 <span style="color: #0000ff">AS</span> ProductLine1Cost,
    NewCol02 <span style="color: #0000ff">AS</span> ProductLine2Cost,
    ...
    NewColX <span style="color: #0000ff">AS</span> ProductLineXCost
<span style="color: #0000ff">FROM</span> SourceTable
<span style="color: #0000ff">WHERE</span> Product <span style="color: #808080">LIKE</span> <span style="color: #ff0000">'%ProductLine1%'</span>

<span style="color: #0000ff">UNION</span> <span style="color: #808080">ALL</span>

<span style="color: #0000ff">SELECT</span> Product, SubProduct, <span style="color: #ff00ff">SUM</span>(Cost) <span style="color: #0000ff">AS </span>TotalCost,
    <span style="color: #ff00ff">SUM</span>(NewCol01) <span style="color: #0000ff">AS</span> TotalProductLine1Cost,
    <span style="color: #ff00ff">SUM</span>(NewCol02) <span style="color: #0000ff">AS</span> ProductLine2Cost,
    ...
    <span style="color: #ff00ff">SUM</span>(NewColX) <span style="color: #0000ff">AS</span> ProductLineXCost
<span style="color: #0000ff">FROM</span> #tempTableX
<span style="color: #0000ff">GROUP BY</span> Product, SubProduct</pre>
<p>This is, of course, a generalized version of the SQL I had just been exposed to, but this was the basic methodology of every &#8220;page&#8221; in this report, and to my dismay just about every bit of SQL NULL Man ever created.  I asked him why he decided to take this approach, and to my utter bemusement, his response was, &#8220;It&#8217;s more efficient!&#8221;.  Ironic really, because any work being performed in the database at this point was a waste.</p>
<p>After verifying that every &#8220;page&#8221; of the report followed the pattern outlined above, I &#8220;optimized&#8221; the entire report into a simple query:</p>
<pre><span style="color: #0000ff">SELECT </span>Product, SubProduct, Cost
<span style="color: #0000ff">FROM</span> SourceTable</pre>
<p>The bulk of the work was done in Excel with Computed Columns, Filters, and Grouping.  This whole process, from evaluation of the existing report to creation of the new one took a grand total of 4 hours, start to finish.  I sent the report onto our Director and the CFO and told them they could refresh the report at any time so they no longer needed to wait on us for up-to-date numbers.  NULL Man voiced his concern that the CFO might not fully understand how to use Excel, but eventually shrugged and said, &#8220;I told &#8216;em it&#8217;d be easier if we let Excel handle most of the work, but they didn&#8217;t listen.&#8221;  It was at this point I knew my future with this company would comprise of fixing and optimizing NULL Man&#8217;s work.</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/null-man/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Jim&#8217;s Keys</title>
		<link>http://shouldhavepaidmemore.com/2009/jims-keys/</link>
		<comments>http://shouldhavepaidmemore.com/2009/jims-keys/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 18:49:09 +0000</pubDate>
		<dc:creator>spork</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Users]]></category>
		<category><![CDATA[coworkers]]></category>
		<category><![CDATA[plus]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=106</guid>
		<description><![CDATA[He saw a set of blank data entry forms assigned to the new schedule instead of all the data he'd already entered under the old schedule.]]></description>
			<content:encoded><![CDATA[<p>Note: You may wish to read <a title="Jim's Comments" href="http://shouldhavepaidmemore.com/2009/10/02/jims-comments">Part I</a>, <a title="Jim's Themes and Dancing Monkeys" href="http://shouldhavepaidmemore.com/2009/10/08/jims-themes-and-dancing-monkeys">Part II</a>, <a title="Jim's Tables" href="http://shouldhavepaidmemore.com/2009/10/10/jims-tables/">Part III</a>, <a title="Jim's Tomcat Server" href="http://shouldhavepaidmemore.com/2009/10/17/jims-tomcat-server/">Part IV</a>, and <a title="Jim's Opus" href="http://shouldhavepaidmemore.com/2009/jims-opus/">Part V</a> of this series to gain context.</p>
<p>As relayed in previous posts in this series, the Plus application was meant to facilitate the transmission of data from field technicians to the home office. However, at some point it was decided that Plus should <em>also</em> be responsible for transmitting and displaying data from the home office to the field technicians. This information ended up being things like equipment-specific metadata, customer contact numbers, location of each piece of equipment, a directory of everyone employed at the company that developed Plus (no, I&#8217;m not kidding), and schedule data. All of this came from a poorly-standardized, non-normalized database used by the company&#8217;s CRM application, <a title="Clearview" href="http://www.nexterna.com/clearview" target="_blank">Nexterna Clearview</a>, which uses a batch-and-post system. <span id="more-106"></span></p>
<p>The schedule data was an important piece because it gave the field technicians a way to see scheduled work without having to use any brainpower. After adding this information to the Plus application the powers that be decided Plus should use it to automatically determine and display the appropriate data forms for the technician to fill out for each site visit. It was further decided that the forms themselves should dynamically change based on the equipment information from the CRM application.</p>
<p>Eventually this was all made ready and deployed to the field technicians. As usual, there were exclamations of &#8220;Wow, this is great!&#8221; and &#8220;This will make us so much more efficient!&#8221; at first. But soon the users started reporting problems. They&#8217;d enter data into a form and it would disappear the next time they downloaded schedule updates from the home office. It turned out Jim built Plus and the <a title="Jim's Tomcat Server" href="http://shouldhavepaidmemore.com/2009/jims-tomcat-server/" target="_blank">Plus server</a> to use auto-generated database record IDs as unique identifiers for schedule data. When a field technician entered form data, it was tied to the schedule&#8217;s database record ID. When the form data was sent to the home office, the Plus server displayed it to home office users by establishing a link between the schedule&#8217;s database record ID and the record ID in the returned data. In a normal world, this wouldn&#8217;t be a problem &#8211; using database keys guaranteed to be unique is good practice, right?</p>
<p>The issue came into play when one of the schedulers at the home office altered a schedule after a field technician had already used Plus to enter form data. The scheduler, called a &#8216;CSAM&#8217;, would change the schedule&#8217;s location, equipment, date, assigned technician, and even go so far as to delete the schedule altogether and create a new one in its stead. The next time the field technician used Plus, he saw a set of blank data entry forms assigned to the new schedule instead of all the data he&#8217;d already entered under the old schedule. In essence, data entered into Plus was &#8220;lost&#8221; due to the normal day-to-day operation of the CSAMs.</p>
<p>Later I found that there had been many a heated argument betwixt Jim and <a title="benson's profile" href="http://shouldhavepaidmemore.com/author/benson/" target="_blank">benson</a> about the use of auto-generated database record IDs as data keys. &#8220;That&#8217;s not how the users work!&#8221; benson would exclaim. &#8220;It&#8217;s the right way to do things!&#8221; Jim would shoot back. The end result was always the same &#8211; Jim would simply continue the way he wanted.</p>
<p>For quite some time people just blamed Plus for everything. &#8220;This stupid tool loses my data!&#8221; they&#8217;d gripe. &#8220;It eats my work!&#8221; Eventually I was able to show that a very small change to the existing CSAM scheduling process could avoid the majority of these situations, and the complaints changed to&#8230;well, they didn&#8217;t change at all. Everyone still made Plus the scapegoat, and the CSAM group refused to believe they could possibly have anything to do with the issues. Their leader wasn&#8217;t willing to even admit it was a possibility.</p>
<p>Finally I rewrote enormous chunks of the Plus application to use less volatile keys that mapped more directly to the way the users worked (vindication for you, <a title="benson's profile" href="http://shouldhavepaidmemore.com/author/benson/" target="_blank">benson</a>). Of course, at the same time the CSAM group finally conceded to make that one tiny change (it took the head of the company to get even that), and they&#8217;re taking credit for reducing the number of issues with Plus data. Oh well, only 11 more days&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/jims-keys/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Double Take</title>
		<link>http://shouldhavepaidmemore.com/2009/double-take/</link>
		<comments>http://shouldhavepaidmemore.com/2009/double-take/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 14:28:01 +0000</pubDate>
		<dc:creator>benson</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=102</guid>
		<description><![CDATA[Sure enough as I debugged the code it was always zero.  So it was completely useless.]]></description>
			<content:encoded><![CDATA[<p>Below you will see some code I ran into a couple days ago.  It is one of those things that took me back to 3rd grade math and made me second guess myself.  If you look there is a new integer declared and it is set to zero.  Then a loop starts in reverse order to iterate through some tabs which are always going to be a quantity of 5.  What is interesting is that the integer is multiplied by -1.  At first glance it made sense, multiply 1 times -1 you get -1, 2 times -1 = -2.  But the value of intTabCounter was never being set inside the loop.  So it appears that it was always zero.  And sure enough as I debugged the code it was always zero.  So it was completely useless.</p>
<p><code>Dim intTabCounter As Integer = 0</code></p>
<p><code> </code></p>
<p><code>For intTabIndex As Integer = tcNewsDayTabs.Tabs.Count - 1 To 0 Step -1<br />
tabDate = Date.Today.AddDays((intTabCounter * -1))<br />
tabDate = NewsUtil.FindBusinessDayDate(tabDate.AddDays(1), ldTabPanelDates)<br />
ldTabPanelDates.Add(intTabIndex, tabDate)<br />
Next intTabIndex<br />
</code></p>
<p>This is an example of a time something looks good on the surface but has no functional value once you look a little deeper.  In a bad economy like we have these days I look at this as job security.</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/double-take/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jim&#8217;s Opus</title>
		<link>http://shouldhavepaidmemore.com/2009/jims-opus/</link>
		<comments>http://shouldhavepaidmemore.com/2009/jims-opus/#comments</comments>
		<pubDate>Mon, 19 Oct 2009 13:59:46 +0000</pubDate>
		<dc:creator>spork</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[coworkers]]></category>
		<category><![CDATA[plus]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=99</guid>
		<description><![CDATA[Note: You may wish to read Part I, Part II, Part III, and Part IV of this series to gain context.
As demonstrated in Part I, Part II, Part III, and Part IV of this series, the Plus application was a mess. It never really worked and when the desired functionality was simulated, it caused other issues. To be fair, the [...]]]></description>
			<content:encoded><![CDATA[<p>Note: You may wish to read <a title="Jim's Comments" href="http://shouldhavepaidmemore.com/2009/10/02/jims-comments">Part I</a>, <a title="Jim's Themes and Dancing Monkeys" href="http://shouldhavepaidmemore.com/2009/10/08/jims-themes-and-dancing-monkeys">Part II</a>, <a title="Jim's Tables" href="http://shouldhavepaidmemore.com/2009/10/10/jims-tables/">Part III</a>, and <a title="Jim's Tomcat Server" href="http://shouldhavepaidmemore.com/2009/10/17/jims-tomcat-server/">Part IV</a> of this series to gain context.</p>
<p>As demonstrated in <a title="Jim's Comments" href="http://shouldhavepaidmemore.com/2009/10/02/jims-comments">Part I</a>, <a title="Jim's Themes and Dancing Monkeys" href="http://shouldhavepaidmemore.com/2009/10/08/jims-themes-and-dancing-monkeys">Part II</a>, <a title="Jim's Tables" href="http://shouldhavepaidmemore.com/2009/10/10/jims-tables/">Part III</a>, and <a title="Jim's Tomcat Server" href="http://shouldhavepaidmemore.com/2009/10/17/jims-tomcat-server/">Part IV</a> of this series, the Plus application was a mess. It never really worked and when the desired functionality was simulated, it caused other issues. To be fair, the department that requested Plus in the first place was also a mess &#8211; its manager not only couldn&#8217;t manage the department&#8217;s 150 employees, but further had no understanding of what they did or what they were supposed to be doing (and those two things were definitely not the same). As a result, change requests for the Plus application had no order, logic, or sanity, and often contradicted <em>other</em> change requests made by the same department slightly earlier. It was a constant cycle of &#8220;Make this change&#8221; &#8220;Why did you change that? Change it back!&#8221; &#8220;Make this change&#8221;.<span id="more-99"></span></p>
<p>Culpability of the project requester aside, the Plus application was awfully, horribly coded. When eight new complex Swing forms are cached in memory every time the mouse is clicked, you know there are some performance optimization opportunities ripe for consumption. The code&#8217;s terribleness was truly stunning in the same way a 450-pound person is &#8211; you&#8217;re disgusted and feel sorry for their plight but oddly intrigued at the same time because you wonder how they can possibly perform even the most basic of daily tasks.</p>
<p>As noted in previous parts of this series, after being charged with managing communication about the Plus application&#8217;s bugs I could hold back any longer &#8211; I had to dive in and fix some of the problems. It was like coming home every day to a towering stack of food-encrusted dishes &#8211; eventually you just have to clean them up. I fixed a few of the smaller bugs in the codebase, tested the fixes, and checked the changes in to the Subversion repository.</p>
<p>Later that week I sat down to lunch with the rest of the IT squad. The boss was there as usual and had some interesting news. &#8220;I talked to Jim last night,&#8221; he led off (Jim and the boss worked at the same company for years &#8211; when the boss was hired at our company, he brought Jim with him from their old employer). &#8220;He was furious that you changed the Plus code.&#8221;</p>
<p>&#8220;What&#8217;s the problem?&#8221; I asked warily.<br />
&#8220;He was extremely upset because you changed his code,&#8221; the boss said.<br />
&#8220;&#8230;but I <em>fixed</em> it&#8230;&#8221;<br />
&#8220;Yes, I know. But Jim and I talked for a long time tonight. He sees the changes you made as an intrusion. He acted very protective of his code.&#8221;<br />
&#8220;&#8230;but I <em>fixed</em> it&#8230;&#8221;<br />
&#8220;Jim said it was like defacing a masterpiece. He called Plus his opus.&#8221;<br />
&#8220;His <em>opus</em>? That&#8217;s normally used to describe an <em>accomplishment</em>. He considers <em>Plus</em> his greatest achievement?! Those saps who hired him are in for a surprise!&#8221;</p>
<p>Ahh, they definitely should have paid me more to put up with this.</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/jims-opus/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Jim&#8217;s Tomcat Server</title>
		<link>http://shouldhavepaidmemore.com/2009/jims-tomcat-server/</link>
		<comments>http://shouldhavepaidmemore.com/2009/jims-tomcat-server/#comments</comments>
		<pubDate>Sun, 18 Oct 2009 05:59:31 +0000</pubDate>
		<dc:creator>spork</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[coworkers]]></category>
		<category><![CDATA[plus]]></category>

		<guid isPermaLink="false">http://shouldhavepaidmemore.com/?p=92</guid>
		<description><![CDATA[The application just zipped the schedule data into a temp directory and sent the file path back to the client.]]></description>
			<content:encoded><![CDATA[<p>Note: You may wish to read <a title="Jim's Comments" href="http://shouldhavepaidmemore.com/2009/10/02/jims-comments">Part I</a>, <a title="Jim's Themes and Dancing Monkeys" href="http://shouldhavepaidmemore.com/2009/10/08/jims-themes-and-dancing-monkeys">Part II</a>, and <a title="Jim's Tables" href="http://shouldhavepaidmemore.com/2009/10/10/jims-tables/">Part III</a> of this series to gain context.</p>
<p>One of the prevailing requirements for <a href="http://shouldhavepaidmemore.com/2009/10/02/jims-comments/">the Plus application</a> was that it allow field staff to enter data offline and &#8220;sync&#8221; it over the Interwebs at their leisure. In addition, the application had to get updated schedule information and previously-synced data and show it to the user while offline. As you know, the most logical design that meets this requirement is a disconnected client-server model. Therefore, a server had to be built to accept connections from the client, process incoming data, and send back schedule  information and previously-synced data.<span id="more-92"></span></p>
<p>This by itself isn&#8217;t such a big deal, right? <a title="Tomcat" href="http://tomcat.apache.org/">Apache Tomcat</a> exists <em>just</em> for tasks of this nature. It&#8217;s an entire server container that&#8217;s mature, been heavily tested, well-maintained, and trusted by enormous companies that could easily afford to choose any server product on Earth. It includes all sorts of advanced configuration options, logging facilities, exception handling, and standards adherence. There&#8217;s even a Windows installer package available! Installation, configuration, and basic Java implementation is fast and easy.</p>
<p>But since this was Jim&#8217;s project, it wasn&#8217;t fast, easy, simple, logical, standards-based, or maintainable. Jim rolled his own Tomcat server instead. Yes, that&#8217;s right &#8211; he ignored the ready-built server software available and wrote his own software to do the same thing. However, his version didn&#8217;t have the benefit of testing&#8230;or configuration options&#8230;or exception handling&#8230;or standards compliance&#8230;or maintainability&#8230;or &#8211; well, you get the idea. As a result, Jim&#8217;s Tomcat didn&#8217;t really work.</p>
<blockquote><p>As anyone might imagine, the directory quickly grew and eventually consumed all disk space on the server, crashing it.</p></blockquote>
<p>Jim split the server implementation into two completely separate areas of the server itself. The actual application itself was only responsible for receiving client requests for schedule information &#8211; but not for sending the data itself back to the client. Instead, the application just zipped the schedule data into a temp directory and <strong>sent the file path</strong> back to the client. The client then connected to an SFTP server and downloaded the specified file. When the client needed to download previously-submitted data files, it connected to the same SFTP server, navigated to a hard-coded directory, and downloaded everything in it. Yes, that&#8217;s right &#8211; <strong>each user ended up downloading all data ever submitted by any of the 150 users every time the client updated</strong>. As anyone might imagine, the directory quickly grew and eventually consumed all disk space on the server, crashing it.</p>
<p>The <em>submission </em>of data, however, was handled by the client. The client connected to that same SFTP server, navigated to a hard-coded directory, and uploaded individual files to it. Then a cron job ran every 60 seconds, swept the directory, determined the type of each data file by matching the beginning of its filename, loaded the data into a database, and moved the files to the &#8220;submitted data&#8221; folder that every client downloaded. If a file couldn&#8217;t be read, the cron job died and any file not already loaded was left in the folder. The next time the cron job ran the same problem would occur&#8230;without any notification to anyone.</p>
<p>I inherited all of this when I was stuck with the Plus project. Had I known what I was getting into, I would&#8217;ve said &#8220;You&#8217;ve gotta pay me more.&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://shouldhavepaidmemore.com/2009/jims-tomcat-server/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
