<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>The Coding Hillbilly</title>
    <link>http://kyle.baley.org/</link>
    <description>Our standards are very low</description>
    <language>en-us</language>
    <copyright>Kyle Baley</copyright>
    <lastBuildDate>Thu, 24 Sep 2009 02:04:26 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.0.7226.0</generator>
    <managingEditor>kyle@baley.org</managingEditor>
    <webMaster>kyle@baley.org</webMaster>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/TheCodingHillbilly" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=7ec5d743-8c7c-4372-aaab-0bdcb35467db</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,7ec5d743-8c7c-4372-aaab-0bdcb35467db.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,7ec5d743-8c7c-4372-aaab-0bdcb35467db.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=7ec5d743-8c7c-4372-aaab-0bdcb35467db</wfw:commentRss>
      
      <title>TeamCity and CodeBetter update, or &amp;ldquo;How to move past the honeymoon phase&amp;rdquo;</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,7ec5d743-8c7c-4372-aaab-0bdcb35467db.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/2Nk1TLUFfzI/TeamCityAndCodeBetterUpdateOrLdquoHowToMovePastTheHoneymoonPhaserdquo.aspx</link>
      <pubDate>Thu, 24 Sep 2009 02:04:26 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
The one year anniversary of when the &lt;a href="http://teamcity.codebetter.com"&gt;TeamCity/CodeBetter&#xD;
collaboration&lt;/a&gt; was brought online. The reason I know this is because the product&#xD;
has a helpful feature whereby it warns you quite clearly at the top of the page when&#xD;
your license is about to expire. Several others noticed this and Jayzus bless Twitter&#xD;
for keeping those kind reminders out of my inbox.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
At last count, we had 49 projects with 77 build configurations. I always like browsing&#xD;
through each one’s website to see what people are working on. Three that caught my&#xD;
fancy that I hadn’t heard of previously are HORN, UppercuT, and crap4n. By the way,&#xD;
I really do mean “last count” because as far as I can tell, there is no way to export&#xD;
a list of projects and/or configurations (see my wish list later in this post).&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
There have been some growing pains of course but for the most part, things are running&#xD;
smoothly now. Over the last year, we’ve added two more agents, Silverlight support,&#xD;
and Git support (through a community plug-in; official version is slated for November).&#xD;
We’re in the process of installing a version of NCover that doesn’t require an administrator&#xD;
to run (thanks to Stephen, Daniel, Joe, and Peter at NCover for their work on this).&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
A couple of projects haven’t made it up yet because of edge-case requirements. XNA&#xD;
support still eludes us as that requires more hoops than any of us have had time.&#xD;
I’m also looking through the list and noticed one that got me excited which is hopefully&#xD;
going to go up soon.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
After working with TeamCity for a large number of projects, I’m generally very happy&#xD;
with it. It was clearly not designed to manage a public portal of OSS projects like&#xD;
this but it’s held up well to the challenge. That said, I do have a wish list of features&#xD;
for an “OSS Portal” edition of the product:&#xD;
&lt;/p&gt;&#xD;
        &lt;ul&gt;&#xD;
          &lt;li&gt;&#xD;
Ability to sort projects by name on the main page. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Ability to collapse projects in the admin page. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
A proper URL field so I don’t have to embed it in the project’s description. A spot&#xD;
for a logo would be nice too. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Quick navigation to a project/configuration. Maybe some shortcut keys or a filter&#xD;
box at the top. The dropdown list under the Projects tab has one. Be nice if the page&#xD;
itself did too. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Easy way to notify all project administrators of upcoming maintenance &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Display project administrators somewhere prominent for each project on the main page&#xD;
and on the admin page &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Configure Visible Projects: C’mon, JetBrains. You’re not Microsoft. Use checkboxes,&#xD;
not that goofy dual ListBox dialog. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Stats or report page showing a list of projects. Optionally, it would show each build&#xD;
configuration for each project and the last time that configuration was run. &#xD;
&lt;ul&gt;&lt;li&gt;&#xD;
Alternatively, they could just add a print stylesheet to the main page because all&#xD;
the info I need is there, except the project administrator. It’s just not conducive&#xD;
to inserting into blog posts… &#xD;
&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
This is a stretch but I’d like to see a custom project template (Note: NOT the “copy&#xD;
project” feature). Something like a “Standard SVN” project template where all it asks&#xD;
for is the project name, the SVN URL, and the project administrator. Then it would&#xD;
create a project and a default build configuration with pre-selected settings and&#xD;
all I’d need to do is put in the build configuration. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
If it hasn’t been fixed yet, a tray notifier that lets you connect to more than one&#xD;
server. (Someone wasn’t doing their homework when they didn’t include this capability&#xD;
from version 1.) &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Easier way to configure notifications. I.e. from the main page, click “Watch this&#xD;
project” or “Watch this configuration” &#xD;
&lt;/li&gt;&#xD;
        &lt;/ul&gt;&#xD;
        &lt;p&gt;&#xD;
Looking forward to next year’s recap.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Wrapped-Up&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=7ec5d743-8c7c-4372-aaab-0bdcb35467db"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=2Nk1TLUFfzI:42_lodLTcSE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=2Nk1TLUFfzI:42_lodLTcSE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=2Nk1TLUFfzI:42_lodLTcSE:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=2Nk1TLUFfzI:42_lodLTcSE:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=2Nk1TLUFfzI:42_lodLTcSE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/2Nk1TLUFfzI" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,7ec5d743-8c7c-4372-aaab-0bdcb35467db.aspx</comments>
      <category>Continuous Integration</category>
    <feedburner:origLink>http://kyle.baley.org/TeamCityAndCodeBetterUpdateOrLdquoHowToMovePastTheHoneymoonPhaserdquo.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=462b8e4c-165e-47e6-a2a7-4c0f406d0b5d</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,462b8e4c-165e-47e6-a2a7-4c0f406d0b5d.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,462b8e4c-165e-47e6-a2a7-4c0f406d0b5d.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=462b8e4c-165e-47e6-a2a7-4c0f406d0b5d</wfw:commentRss>
      
      <title>Using AutoHotKey to map the Ctrl key, or &amp;ldquo;How to Ctrl your closure&amp;rdquo;</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,462b8e4c-165e-47e6-a2a7-4c0f406d0b5d.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/iFADTSX1bQQ/UsingAutoHotKeyToMapTheCtrlKeyOrLdquoHowToCtrlYourClosurerdquo.aspx</link>
      <pubDate>Thu, 17 Sep 2009 21:21:35 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
Quick productivity blorg today. Because if hillbillies are known for anything, it’s&#xD;
their efficacy. And their ability to use words they don’t quite know the meaning of&#xD;
but can fake in context. (I’m referring, of course, to “efficacy”. I know full well&#xD;
what a “blorg” is so I don’t need you telling me in the comments.)&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Alt-F4 is not the most natural keystroke on the &lt;a href="http://www.kinesis-ergo.com/images/kb_adv-pro_met720x471.jpg"&gt;Kinesis&#xD;
keyboard&lt;/a&gt;. Or even on a regular keyboard. Yet I use it pretty often. Especially&#xD;
recently while testing out Lucene on my document repository. Word and PDF docs abound&#xD;
very quickly while I’m opening them and verifying results. So I was looking for a&#xD;
faster way of closing them quickly.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
My chosen method: Press Ctrl three times in rapid succession to close the active window.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The implementation: &lt;a href="http://www.autohotkey.com/"&gt;AutoHotKey&lt;/a&gt;. Here is &lt;a href="http://pastie.org/612336"&gt;the&#xD;
script&lt;/a&gt; that does it:&#xD;
&lt;/p&gt;&#xD;
        &lt;pre name="code"&gt;~Ctrl::&#xD;
CloseOnThird()&#xD;
return&#xD;
&#xD;
CloseOnThird() {&#xD;
&#xD;
   Static Count&#xD;
   key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^( UP)]")&#xD;
   If ( A_ThisHotKey = A_PriorHotKey and A_TimeSincePriorHotkey &amp;lt; 400 )&#xD;
        Count += Count &amp;lt; 3 ? 1 : 0&#xD;
   Else Count = 1&#xD;
   KeyWait %key%, DT0.4&#xD;
   If (ErrorLevel and Count = 3)&#xD;
      WinClose,A&#xD;
}&lt;/pre&gt;&#xD;
        &lt;p&gt;&#xD;
The end result: at the end of a strenuous day, I can mash the Ctrl key over and over&#xD;
again until the computer shuts down. Tres satisfying.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Ctrl’d&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=462b8e4c-165e-47e6-a2a7-4c0f406d0b5d"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=iFADTSX1bQQ:12IXkFXSkdk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=iFADTSX1bQQ:12IXkFXSkdk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=iFADTSX1bQQ:12IXkFXSkdk:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=iFADTSX1bQQ:12IXkFXSkdk:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=iFADTSX1bQQ:12IXkFXSkdk:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/iFADTSX1bQQ" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,462b8e4c-165e-47e6-a2a7-4c0f406d0b5d.aspx</comments>
      <category>Utilities</category>
    <feedburner:origLink>http://kyle.baley.org/UsingAutoHotKeyToMapTheCtrlKeyOrLdquoHowToCtrlYourClosurerdquo.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=1b07b6d5-1e0f-4581-9429-74e7a276f533</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,1b07b6d5-1e0f-4581-9429-74e7a276f533.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,1b07b6d5-1e0f-4581-9429-74e7a276f533.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=1b07b6d5-1e0f-4581-9429-74e7a276f533</wfw:commentRss>
      
      <title>Search functionality: heavy on the research, light on the development</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,1b07b6d5-1e0f-4581-9429-74e7a276f533.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/0gZ1r6jhL08/SearchFunctionalityHeavyOnTheResearchLightOnTheDevelopment.aspx</link>
      <pubDate>Wed, 16 Sep 2009 14:11:12 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
The word “and” has always bugged me. I hate started sentences with it but sometimes&#xD;
can’t help myself. Whenever I have a list of three or more items in a sentence, I&#xD;
can never tell whether I should be a comma before the “and” separating the last two&#xD;
items. &lt;strike&gt;And &lt;/strike&gt;Plus it causes me no end of grief in search interfaces.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The impetus behind my most recent &lt;a href="http://kyle.baley.org/LucenenetVsIndexingServicesOrLdquoHowToConquerYourFearOfIndexManagementrdquo.aspx"&gt;foray&#xD;
into Lucene.NET&lt;/a&gt; was one query phrase in particular:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
research and development&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Specifically, I want to be able to find documents that contained this phrase in it.&#xD;
Not both the word “research” AND the word “development” but the phrase “research and&#xD;
development”.&lt;strike&gt; And&lt;/strike&gt; Also, preferably it would return documents that&#xD;
contained “research &amp;amp; development” or, if you *really* want to impress someone,&#xD;
“r&amp;amp;d”.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
In the spirit of my search term, I’ve been doing some research and development to&#xD;
try to figure this little query out. More of the latter at first but it’s been increasingly&#xD;
obvious that to do a decent search interface, you also need plenty of the former.&#xD;
To that end, this will be a typically epic free-form meandering of my process with&#xD;
my usual caveat: If any of this is useful to you, that’s not my fault. I won’t go&#xD;
into much detail here because: a) &lt;a href="http://codeclimber.net.nz"&gt;Simone Chiaretta&lt;/a&gt; will&#xD;
almost certainly cover it shortly (if he hasn’t already), and b) there is plenty of&#xD;
documenta---…actually, that’s not true. Oh well, I’m still not covering the inner&#xD;
workings of parsers and analyzers.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;QueryParser.Parse&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
By all accounts, QueryParser is the class to use when dealing with user-entered input.&#xD;
You can use a fairly easy-to-learn syntax and let Lucene handle the heavy lifting&#xD;
of whether to search for an entire phrase or individual words. It also includes a&#xD;
way of parsing AND, OR, or NOT.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This has the most appeal to me for obvious reasons so it was the one I settled on&#xD;
first. Then came “research and development”. Searching for the phrase with quotes&#xD;
around it came back with false positives. I.e. documents that contained either &lt;em&gt;research&lt;/em&gt; or &lt;em&gt;development&lt;/em&gt;.&#xD;
So I halted the development and started some research.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;StandardAnalyzer&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This led to much reading about Analyzers. (&lt;strike&gt;And&lt;/strike&gt; So I’ll echo many&#xD;
others’ sentiments by recommending the book, Lucene in Action, which has been a great&#xD;
resource.) I started out indexing and searching with the StandardAnalyzer. But this&#xD;
has a couple of side effects. For one, when indexing, it strips out common stop words,&#xD;
like &lt;em&gt;the, a,&lt;/em&gt; and&lt;em&gt; an. &lt;/em&gt;&lt;strike&gt;And&lt;/strike&gt; As well as &lt;em&gt;and.&lt;/em&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
On the search side, it will also do some parsing of the query phrase when you use&#xD;
it with QueryParser.Parse. In short, when you search for “research and development”&#xD;
(with quotes) using a StandardAnalyzer, the query is parsed to the following:&#xD;
&lt;/p&gt;&#xD;
        &lt;blockquote&gt;&#xD;
          &lt;p&gt;&#xD;
contents:”research development”&#xD;
&lt;/p&gt;&#xD;
        &lt;/blockquote&gt;&#xD;
        &lt;p&gt;&#xD;
I.e. The &lt;em&gt;and&lt;/em&gt; is taken out of the search phrase altogether. Not quite what&#xD;
I had in mind so a new track was laid.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;SimpleAnalyzer&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The SimpleAnalyzer indexes everything. Every word (and every position of every word&#xD;
if you tell it to). Obviously, the size of your index will grow considerably. In my&#xD;
testing ground, it quintupled in size from 19Mb to 100Mb based on 1600-odd Word and&#xD;
PDF documents.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
On the search side, if you use a SimpleAnalyzer with the QueryParser, it does correctly&#xD;
identify the phrase “research and development” when you include it in quotes. So all&#xD;
appears happy and good…&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
…except that it doesn’t handle “r&amp;amp;d” (with or without the quotes) very well. The&#xD;
query is reduced to:&#xD;
&lt;/p&gt;&#xD;
        &lt;blockquote&gt;&#xD;
          &lt;p&gt;&#xD;
contents:”r d”&#xD;
&lt;/p&gt;&#xD;
        &lt;/blockquote&gt;&#xD;
        &lt;p&gt;&#xD;
I.e. Find all documents with the letter &lt;em&gt;r&lt;/em&gt; and the letter &lt;em&gt;d&lt;/em&gt; as individual&#xD;
letters in them. Which, truth be told, isn’t such a bad thing on the surface. It means&#xD;
we’ll catch not only documents containing “r&amp;amp;d” but also those containing “R &amp;amp;&#xD;
D”. But by the same token (pun intended), it will also match documents containing&#xD;
“R. Buford D. Justice”&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;PhraseQuery&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Another option I looked at was the PhraseQuery. If you use this, it will always search&#xD;
for the exact phrase. None o’ this “research development” or “r d” nonsuch.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
But here, the analyzers come into play as well. If I search for “research and development”,&#xD;
that means the word &lt;em&gt;and&lt;/em&gt; needs to be indexed. Which implies a SimpleAnalyzer&#xD;
during indexing. If I search for “r&amp;amp;d”, the SimpleAnalyzer won’t work because&#xD;
it breaks up words separated by ampersand.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;From here…&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
That brings everyone up to speed to where I am now. I’ve posed the question on &lt;a href="http://stackoverflow.com/questions/1430049/lucene-net-search-phrase-containing-and"&gt;StackOverflow&lt;/a&gt; (my&#xD;
first!) and at the moment, the only answer to it suggests I write my own analyzer,&#xD;
one that acts like the StandardAnalyzer but doesn’t throw out the word &lt;em&gt;and&lt;/em&gt;.&#xD;
That sounds reasonable to me, at least until someone searches for “research or development”.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Another option I’m considering is to tell the indexer to index specific phrases like&#xD;
“research and development” or “oil and gas” or other common ones used in the domain.&#xD;
Not sure I like the long-term maintenance of either option but search is a journey,&#xD;
not a destination, I suppose.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
There’s a fundamental argument buried in here somewhere. Lucene gives you so much&#xD;
control over your indexing/searching that if you’re one of those Type A’s that can’t&#xD;
stand when something is just “good enough”, you can very easily drive yourself up&#xD;
the wall trying to optimize things. It really does require you to put some thought&#xD;
into how users will use your search. As much as Microsoft Indexing Services allowed&#xD;
me to throw up a search interface haphazardly, I believe you do yourself an injustice&#xD;
by not considering the ins and outs of the process.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
By the way, a couple people asked about the code I used to extract text from Word&#xD;
and PDF docs. Lovingly provided by the venerable (and I hope I used the right word&#xD;
there) &lt;a href="http://www.persistall.com"&gt;Brian Donahue&lt;/a&gt;, the relevant classes&#xD;
are attached in their entirety. The only thing different about this code snippet compared&#xD;
to others I’ve been sent in the past is that this one worked out of the box with absolutely&#xD;
no help from me. Seriously, I can’t even tell you what the internal method names are,&#xD;
that’s how little I looked at it. Call Parser.Parse(filename) and watch the magic&#xD;
fly.&#xD;
&lt;/p&gt;&#xD;
        &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:791bff2a-b825-4e82-8474-7f7e23858bc9" class="wlWriterEditableSmartContent"&gt;&#xD;
          &lt;p&gt;&#xD;
            &lt;a href="http://kyle.baley.org/content/binary/WindowsLiveWriter/b684f6ecc60b_143CF/Parser_1.txt" target="_blank"&gt;Filter.cs&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a href="http://kyle.baley.org/content/binary/WindowsLiveWriter/b684f6ecc60b_143CF/Filter_1.txt" target="_blank"&gt;Parser.cs&lt;/a&gt;&#xD;
          &lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Found-ational&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=1b07b6d5-1e0f-4581-9429-74e7a276f533"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=0gZ1r6jhL08:pd5Hda1yhIs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=0gZ1r6jhL08:pd5Hda1yhIs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=0gZ1r6jhL08:pd5Hda1yhIs:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=0gZ1r6jhL08:pd5Hda1yhIs:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=0gZ1r6jhL08:pd5Hda1yhIs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/0gZ1r6jhL08" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,1b07b6d5-1e0f-4581-9429-74e7a276f533.aspx</comments>
      <category>Lucene.NET</category>
    <feedburner:origLink>http://kyle.baley.org/SearchFunctionalityHeavyOnTheResearchLightOnTheDevelopment.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=d06141fd-0548-4def-8fd9-82f5b349200e</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,d06141fd-0548-4def-8fd9-82f5b349200e.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,d06141fd-0548-4def-8fd9-82f5b349200e.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=d06141fd-0548-4def-8fd9-82f5b349200e</wfw:commentRss>
      <slash:comments>3</slash:comments>
      
      <title>Lucene.net vs. Indexing Services, or &amp;ldquo;How to conquer your fear of index management&amp;rdquo;</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,d06141fd-0548-4def-8fd9-82f5b349200e.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/zL6QkDJ3vMU/LucenenetVsIndexingServicesOrLdquoHowToConquerYourFearOfIndexManagementrdquo.aspx</link>
      <pubDate>Thu, 10 Sep 2009 16:26:20 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
Long-winded background for this long-winded post can be found &lt;a href="http://codebetter.com/blogs/kyle.baley/archive/2008/05/13/researching-search.aspx"&gt;here&lt;/a&gt; and &lt;a href="http://codebetter.com/blogs/kyle.baley/archive/2008/07/07/trying-to-access-windows-search-from-sql-server-an-appeal.aspx"&gt;here&lt;/a&gt;.&#xD;
The short version is: I have an app that searches using a full-text search of a document&#xD;
repository consisting of Office docs and PDFs.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The current version uses Microsoft Indexing Service and it is all but obsolete. Which&#xD;
is fine with me for the time being because of the economics of the situation. Namely,&#xD;
the app isn’t big enough to warrant putting the effort into updating it just for the&#xD;
sake of the technology.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Two things happened recently though that made me decide it &lt;em&gt;was&lt;/em&gt; time to update.&#xD;
First was &lt;a href="http://codeclimber.net.nz/"&gt;Simone Chiaretta’s masterfully-timed&#xD;
tutorial series&lt;/a&gt; on getting started with Lucene.NET. The second was the boss discovering&#xD;
the current version doesn’t actually work.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
By many orders of magnitude, the boss is the biggest user of this application. And&#xD;
recently, he went about searching for a relatively common term: R&amp;amp;D. He was met&#xD;
with a nicely formatted 500 Server Error page and asked me if I would be so bold as&#xD;
to fix it.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
A day and a half later and I simply had no fix. The existing app uses a SQL query&#xD;
to search the Indexing Service which, at the time, I thought was tres clever. But&#xD;
after trying a dozen methods of escaping it, there was no way I could get it to accept&#xD;
an ampersand. Furthermore, I also discovered the page failed when including words&#xD;
like ‘AND’ and ‘OR’. This problem was fixable but required some parsing of the search&#xD;
term and again, the cost/benefit for making this sort of thing bullet-proof just wasn’t&#xD;
there.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
So when Simone’s tutorial started coming across my RSS feed, it just made sense to&#xD;
re-think the problem.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The main reason I resisted moving away from Indexing Service for so long is thus:&#xD;
I don’t need to manage the index myself. Once configured, the only thing I needed&#xD;
to do to add a document to the index was drop it into a folder.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
But therein lay the problem: Because I don’t manage the index, I have no control over&#xD;
it. During my travels, I discovered I was getting false positives for some terms and&#xD;
that it was not returning all documents in some cases.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
How did I discover this? I implemented Lucene and compared the results. If I discovered&#xD;
a discrepancy and it was because of how I indexed with Lucene, well, then I tweaked&#xD;
the indexing process. If the discrepancy was with Indexing Services…well, then I said,&#xD;
“&amp;amp;*%$ it! You’re getting replaced!”&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Another bit of fortuitousness came in the form of one &lt;a href="http://www.persistall.com/"&gt;Brian&#xD;
Donahue&lt;/a&gt;. One of my fears going into this was how I would get the text out of the&#xD;
documents in order to index it. I had waking nightmares of Windows API calls and IFilters,&#xD;
dreading having to deal with this. So when, after outlining my pain on Twitter, Brian&#xD;
responded with, and I’m paraphrasing, “Here, take this code. It will do that for you&#xD;
and it WORKS RIGHT OUT OF THE BOX!”. I don’t mind admitting I developed an unhealthy&#xD;
infatuation with him for a short time after that.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
In fact, it was through the process of managing the index myself with Lucene that&#xD;
I discovered one reason some documents weren’t getting indexed. They were RTF documents&#xD;
but they had a .doc extension so it was using the wrong IFilter to capture the text.&#xD;
It was through Brian’s code for extracting text that I figured this out. It threw&#xD;
errors on some documents and I couldn’t figure out why until I tried to Save As… when&#xD;
working with them in Word. Change the extension to its rightful .rtf and the indexing&#xD;
process hummed along. But with the Indexing Service, these documents simply weren’t&#xD;
indexed. No error, no notification. It’s possible a message was posted to the event&#xD;
log but that’s a little too passive even for me.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I hope to have some more technical details but I want to wait until Simone is further&#xD;
along so I don’t duplicate. I’ll very likely piggy-back off a couple of his posts&#xD;
but to summarize: Lucene.NET rocks and should be used any time you have a button labeled&#xD;
“Search”, “Find”, “Locate”, or “Git it!” Fear not the index-management process because&#xD;
like WebForms, the problem isn’t hard enough that it needs to be abstracted.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Co-located&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=d06141fd-0548-4def-8fd9-82f5b349200e"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=zL6QkDJ3vMU:3I5U778nwc0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=zL6QkDJ3vMU:3I5U778nwc0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=zL6QkDJ3vMU:3I5U778nwc0:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=zL6QkDJ3vMU:3I5U778nwc0:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=zL6QkDJ3vMU:3I5U778nwc0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/zL6QkDJ3vMU" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,d06141fd-0548-4def-8fd9-82f5b349200e.aspx</comments>
      <category>Lucene.NET</category>
    <feedburner:origLink>http://kyle.baley.org/LucenenetVsIndexingServicesOrLdquoHowToConquerYourFearOfIndexManagementrdquo.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=d5d1fd62-8b32-4c0f-8530-3080e964eee5</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,d5d1fd62-8b32-4c0f-8530-3080e964eee5.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,d5d1fd62-8b32-4c0f-8530-3080e964eee5.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=d5d1fd62-8b32-4c0f-8530-3080e964eee5</wfw:commentRss>
      
      <title>Death of a user group, or &amp;ldquo;How to give up&amp;rdquo;</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,d5d1fd62-8b32-4c0f-8530-3080e964eee5.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/ddlvt2EgR24/DeathOfAUserGroupOrLdquoHowToGiveUprdquo.aspx</link>
      <pubDate>Wed, 09 Sep 2009 13:52:14 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
Bahamas Software Development User Group, we hardly knew ye.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
It’s been just over a year since I started the short-lived group but alas! It is no&#xD;
more. In this post-mortem, we discuss What Went Wrong by providing smug pieces of&#xD;
advice fueled by 20/20 hindsight.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Know what you’re getting into&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
As much as you’d like to keep the process lean, there is &lt;em&gt;always&lt;/em&gt; work to be&#xD;
done. Initially, you may be required to give the majority of the presentation. There&#xD;
may be sponsors to solicit, presenters to organize, and government officials to appease&#xD;
when you try to explain that that box of lasciviously-shaped USB keys is for an upcoming&#xD;
“code camp”.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Get help&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
If you want to follow the Ozark Symphony Orchestra around on its whirlwind tour of &lt;a href="http://en.wikipedia.org/wiki/Athens,_Arkansas"&gt;Athens&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Prague,_Oklahoma"&gt;Prague&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Vienna,_Georgia"&gt;Vienna&lt;/a&gt;,&#xD;
and &lt;a href="http://en.wikipedia.org/wiki/Paris,_Missouri"&gt;Paris&lt;/a&gt;,  you’ll&#xD;
need someone to fill in for you. A group run by a single person isn’t a group.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Be prepared for skepticism&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Okay, this one surprised me when I made up my list. And since I recognize the perils&#xD;
of having unwavering optimism, it shouldn’t have. Many people I talked to came up&#xD;
with half a dozen reasons why it wouldn’t work: people are too secretive, it’s just&#xD;
another marketing tool for Company X, I work all day so why would I bother coming&#xD;
out in the evening.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The culmination of this was when one person accused me of using the group as a front&#xD;
to bring my “cronies” in to steal jobs from Bahamians and threatened to call the immigration&#xD;
department on me. Which is odd since I don’t work for a local company. Short version:&#xD;
some people will always look at what you aren’t doing rather than what you are.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Be flexible&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I started the group as a .NET-specific one. In the group’s death throes, I broadened&#xD;
the scope to software development in general to account for the small size of the&#xD;
population and the wide variety of skills and interests. Many people are web designers&#xD;
who have had to learn programming to meet customer demands. And a session titled “Integrating&#xD;
Sharepoint with BizTalk” probably won’t have much relevance.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Know your public&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This was, I believe, the one that effectively killed the group. I’ll have a follow-up&#xD;
post on it with more specifics when I’m able to keep my frustration at bay and can&#xD;
talk about it diplomatically.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
In the end, whatever external factors exist, the primary reason the group didn’t work&#xD;
is because I didn’t have the fortitude to see it through. Maybe it was arrogance,&#xD;
maybe it was naiveté. Probably a bit of both. I wish this was only the first time&#xD;
I started something without anything more than good intentions. I doubt I’m the only&#xD;
one that starts things like this with an optimistic “let’s see what happens” without&#xD;
giving much thought into the work involved but it’s still kind of embarrassing that&#xD;
I folded up effectively because I didn’t feel like putting in the effort anymore.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I’d call it a lesson learned but we all know better…&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Unimproved&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=d5d1fd62-8b32-4c0f-8530-3080e964eee5"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ddlvt2EgR24:5Jt3DXoKZPU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ddlvt2EgR24:5Jt3DXoKZPU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ddlvt2EgR24:5Jt3DXoKZPU:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=ddlvt2EgR24:5Jt3DXoKZPU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ddlvt2EgR24:5Jt3DXoKZPU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/ddlvt2EgR24" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,d5d1fd62-8b32-4c0f-8530-3080e964eee5.aspx</comments>
      <category>Bahanet</category>
      <category>Community</category>
    <feedburner:origLink>http://kyle.baley.org/DeathOfAUserGroupOrLdquoHowToGiveUprdquo.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=0d0716b8-b949-4427-8d19-3c216174fc0c</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,0d0716b8-b949-4427-8d19-3c216174fc0c.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,0d0716b8-b949-4427-8d19-3c216174fc0c.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=0d0716b8-b949-4427-8d19-3c216174fc0c</wfw:commentRss>
      
      <title>Piquing curiosity, or &amp;ldquo;How to scratch the surface&amp;rdquo;</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,0d0716b8-b949-4427-8d19-3c216174fc0c.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/CYqZZMv9xZ4/PiquingCuriosityOrLdquoHowToScratchTheSurfacerdquo.aspx</link>
      <pubDate>Sat, 29 Aug 2009 19:10:12 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
Another in the series of “reviewer feedback I’m going to deal with using dicey justification&#xD;
techniques” for &lt;a href="http://manning.com/baley"&gt;Brownfield Application Development&lt;/a&gt;.&#xD;
This time, there were concerns that the topics covered in the book don’t go in-depth&#xD;
enough. One reviewer said he or she would need to reference other works in order to&#xD;
learn more.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
My justification for that: Good!&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
We cover a lot of topics in the book. Automated testing, continuous integration, dependency&#xD;
injection, object/relational mappers. Given the scope that we chose, we can’t get&#xD;
in depth. That’s the choice we made when outlining said scope. But if all we’ve done&#xD;
is piqued someone’s interest enough to seek out more information elsewhere, I’ll consider&#xD;
that a success.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
That said, clearly we need to set expectations for the reader. One of the underlying&#xD;
themes of the book is to foster a sense of curiosity and, more importantly, a sense&#xD;
of pride in one’s work. To make the reader aware of potential new things and encourage&#xD;
them to delve deeper. In short, to &lt;em&gt;start&lt;/em&gt; the journey, not to end it. This&#xD;
is where careful wording at the beginning will improve things, I think.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Next up, why we’re not going to take out the alcohol-fueled rants on datasets.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Justified&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=0d0716b8-b949-4427-8d19-3c216174fc0c"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=CYqZZMv9xZ4:WiWr3uxvzbM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=CYqZZMv9xZ4:WiWr3uxvzbM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=CYqZZMv9xZ4:WiWr3uxvzbM:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=CYqZZMv9xZ4:WiWr3uxvzbM:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=CYqZZMv9xZ4:WiWr3uxvzbM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/CYqZZMv9xZ4" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,0d0716b8-b949-4427-8d19-3c216174fc0c.aspx</comments>
      <category>Brownfield</category>
      <category>Writing</category>
    <feedburner:origLink>http://kyle.baley.org/PiquingCuriosityOrLdquoHowToScratchTheSurfacerdquo.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=d67c0d91-b04c-412a-8ab4-99d7e01002d3</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,d67c0d91-b04c-412a-8ab4-99d7e01002d3.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,d67c0d91-b04c-412a-8ab4-99d7e01002d3.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=d67c0d91-b04c-412a-8ab4-99d7e01002d3</wfw:commentRss>
      <slash:comments>1</slash:comments>
      
      <title>Gondorff and Hooker vs. Butch and Sundance</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,d67c0d91-b04c-412a-8ab4-99d7e01002d3.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/ea8h6xWq8gI/GondorffAndHookerVsButchAndSundance.aspx</link>
      <pubDate>Fri, 14 Aug 2009 15:00:56 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
At the beginning of the project I’m on, I made a humbling mistake. There were two&#xD;
others on the team, an employee and another contractor. The mandate the other contractor&#xD;
and I were given was to introduce some new techniques to the employees which is all&#xD;
hunky-dory.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The other contractor is a young’un, over ten years my junior. I had interviewed him&#xD;
for another position in the company some months earlier and to his benefit, we didn’t&#xD;
take him on for that one. He’s a developer at heart, it would have been his first&#xD;
contract, and it was for a Livelink position. My rationale was that he’d have left&#xD;
within three months. But when I joined the new project, I was glad to hear they picked&#xD;
him up for it. During the interview, he said all the right things: read blogs, interested&#xD;
in continuous improvement, always honing his craft, etc, etc.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
In short, someone with the right attitude but perhaps short on experience. Someone&#xD;
I could mold into a veritable hillbilly powerhouse!&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
(Now there are a couple of ways this story can end with this set up. First: I take&#xD;
him under my wing, put him on the path of righteousness, and unleash him on the world&#xD;
to make it a better place. That’s boring and I wouldn’t blog it. The more entertaining&#xD;
way is that he turns out to be a fraud and that it was actually his evil twin brother&#xD;
we interviewed. I’ll disappoint and say that that didn’t happen either.)&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
So my mindset going in was as the wizened old sagacious consultant descended from&#xD;
upon high to bestow his wisdom on the team. After all, the kid was barely out of diapers.&#xD;
He needed direction. DIRECTION, I TELL YOU!!!&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I’ll paraphrase one of our early conversations:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;em&gt;Coding Hillbilly (preparing for a long drawn-out follow-up explanation):&lt;/em&gt; Let’s&#xD;
make sure we keep our integration tests separate from our unit tests &#xD;
&lt;br&gt;&lt;em&gt;Assumed greenhorn:&lt;/em&gt; Yeah, I’m down with that fo shizzle. I don’t want to be&#xD;
slowing ourselves down waiting for those suckerz to runz, yo! &#xD;
&lt;br&gt;&lt;em&gt;Coding Hillbilly:&lt;/em&gt; Because they take longer to r—…umm…I mean. Yeah.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Later conversations touched on testing techniques, CI product comparisons, composition&#xD;
vs. inheritance, and dependency injection. In a great many of them, he would disagree&#xD;
with me. But what I wasn’t prepared for is that in almost every case, he disagreed&#xD;
with me for valid and well-thought-out reasons. To the point where my argument degenerated&#xD;
to “oh yeah! Well you’re ugly!” And I even lost that argument because I later discovered&#xD;
he’s done work as a model. One argument we had was doomed from the start when I said,&#xD;
“why are you bothering to test on Firefox when the company has standardized on IE6?”&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
What made all these discussions even more humiliating is that he never shoved his&#xD;
superior knowledge in my face. He was always civil and respectful. But he uses an&#xD;
even worse tactic when I say something clearly wrong: He would always reply with “I&#xD;
see”, then go silent. Allowing me to ruminate on why, in the name of all that is hillbilly,&#xD;
I would claim that it was better to use an &amp;lt;asp:repeater&amp;gt; instead of a &amp;lt;%foreach%&amp;gt;. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This was early in the project, when I was blinded by the “knowledge” that, as the&#xD;
senior developer, whatever I said was always right. Before the kid started, it was&#xD;
clear to me that there was a lot of work to be done training the rest of the team&#xD;
and I was content to take things slowly and use the first project just to get the&#xD;
lay of the land. Then Sundance rolls into town and we’ve now integrated jQuery into&#xD;
the mix, introduced Moq for testing, and refactored our data access layer to use a&#xD;
truer definition of repository. And while not all of this is completely his doing,&#xD;
his perseverance has been a strong contributing factor.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Expectations have since been reset on both sides. Rather than the &lt;a href="http://www.imdb.com/title/tt0070735/"&gt;mentoring&#xD;
relationship&lt;/a&gt; I had expected (and tried to push), it is more of a &lt;a href="http://www.imdb.com/title/tt0064115/"&gt;peer&#xD;
relationship&lt;/a&gt; now. And in the name of continuous improvement, I’ve learned that&#xD;
you never stop learning. From anyone.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Stagnant&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=d67c0d91-b04c-412a-8ab4-99d7e01002d3"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ea8h6xWq8gI:D7OJclRZSac:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ea8h6xWq8gI:D7OJclRZSac:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ea8h6xWq8gI:D7OJclRZSac:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=ea8h6xWq8gI:D7OJclRZSac:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=ea8h6xWq8gI:D7OJclRZSac:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/ea8h6xWq8gI" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,d67c0d91-b04c-412a-8ab4-99d7e01002d3.aspx</comments>
      <category>Professional Development</category>
      <category>Workplace</category>
    <feedburner:origLink>http://kyle.baley.org/GondorffAndHookerVsButchAndSundance.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=174e8cd1-ded4-435e-87e5-f0a984bcf750</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,174e8cd1-ded4-435e-87e5-f0a984bcf750.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,174e8cd1-ded4-435e-87e5-f0a984bcf750.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=174e8cd1-ded4-435e-87e5-f0a984bcf750</wfw:commentRss>
      
      <title>Compile =&gt; CI =&gt; Tests, or "How to compile first, test later"</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,174e8cd1-ded4-435e-87e5-f0a984bcf750.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/4Su1APEgh4I/CompileCITestsOrHowToCompileFirstTestLater.aspx</link>
      <pubDate>Fri, 07 Aug 2009 16:44:23 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
A common piece of feedback we got for early reviews of &lt;a href="http://manning.com/baley"&gt;Brownfield&#xD;
Application Development&lt;/a&gt; is that the automated testing chapter should come before&#xD;
the automated build/continuous integration chapter. This was an awesome bit of feedback&#xD;
mostly because we could ignore it and instead get some air time on my blog on why&#xD;
we're doing it this way.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
When I come into a project, my most immediate goal is usually to get it into a continuous&#xD;
integration environment as soon as possible. And the bare minimum for that is to get&#xD;
the source code and compile it. If there are tests and they pass, that's an added&#xD;
bonus. I'll add them to the CI process afterward.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
For me, it comes down to treating your environment just as incrementally as your code.&#xD;
I want my CI environment up and running now. Maybe the tests pass, maybe they don't.&#xD;
If I dump them in there now, that adds a variable into the mix I don't want to deal&#xD;
with at the moment.&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
There's some element of personal preference, I suppose. But it's also borne from experience.&#xD;
At one time, I had some minor frustration trying to do everything in the automated&#xD;
build before dumping it on the CI server and having it fail. Just like we check in&#xD;
smaller bits of code more often, I like to enhance my CI process in small chunks more&#xD;
often.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Incidentally, CI is why we cover version control first. Not because we think you don't&#xD;
know anything about version control, but so that you can get your source repository&#xD;
prepared for continuous integration. Any hack can dump code into SVN. The important&#xD;
thing is whether you can get it back in an immediately useful state. Continuous integration&#xD;
can help determine if it's immediately useful.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Alas, the rest of the feedback for the book was not so easily dismissed. Damn you&#xD;
people and your "values".&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Edited&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=174e8cd1-ded4-435e-87e5-f0a984bcf750"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=4Su1APEgh4I:4oEySH4bdeg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=4Su1APEgh4I:4oEySH4bdeg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=4Su1APEgh4I:4oEySH4bdeg:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=4Su1APEgh4I:4oEySH4bdeg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=4Su1APEgh4I:4oEySH4bdeg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/4Su1APEgh4I" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,174e8cd1-ded4-435e-87e5-f0a984bcf750.aspx</comments>
      <category>Brownfield</category>
      <category>Continuous Integration</category>
    <feedburner:origLink>http://kyle.baley.org/CompileCITestsOrHowToCompileFirstTestLater.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=e780ad3a-98fc-468f-ad60-8e3702e33578</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,e780ad3a-98fc-468f-ad60-8e3702e33578.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,e780ad3a-98fc-468f-ad60-8e3702e33578.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=e780ad3a-98fc-468f-ad60-8e3702e33578</wfw:commentRss>
      <slash:comments>3</slash:comments>
      
      <title>Unflattening a list, or "How to ask 'how to'"</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,e780ad3a-98fc-468f-ad60-8e3702e33578.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/jn0DI_PWgtc/UnflatteningAListOrHowToAskHowTo.aspx</link>
      <pubDate>Wed, 05 Aug 2009 13:44:45 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
Code challenge time! And by code challenge, I mean, "Do my work for me so I don't&#xD;
have to think/Google".&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
We have a parent object, called Parent, and each one has a collection of child objects,&#xD;
called AllegedChild. Ignore potential cycles for this exercise. The database has a&#xD;
single table with fields: ParentID, ParentName, ChildID, ChildName. The data is such:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
1, Coding Hillbilly, 1, Brandi-Lynn&lt;br&gt;&#xD;
1, Coding Hillbilly, 2, Sammy-Jo&lt;br&gt;&#xD;
1, Coding Hillbilly, 3, Sammy-Jo Jr.&lt;br&gt;&#xD;
1, Coding Hillbilly, 4, Sammy-Jo Sr.&lt;br&gt;&#xD;
2, Donald Belcham, 5, Justice Gray&lt;br&gt;&#xD;
2, Donald Belcham, 5, Dave Laribee&lt;br&gt;&#xD;
2, Donald Belcham, 5, Scott&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
We will retrieve this list into a collection of ParentChildDto objects with properties&#xD;
that mirror the database. From this list, we'd like to create a new list of Parent&#xD;
objects each with an appropriate list of AllegedChild objects.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The challenge, given a List&amp;lt;ParentChildDto&amp;gt;, what is a clean and efficient way&#xD;
of creating a List&amp;lt;Parent&amp;gt;? The current implementation looks something like&#xD;
this:&#xD;
&lt;/p&gt;&#xD;
        &lt;pre name="code" class="c-sharp"&gt;private List&amp;lt;Parent&amp;gt; GitEm( IEnumerable&amp;lt;ParentChildDto&amp;gt; flatList )&lt;br&gt;&#xD;
{&lt;br&gt;&#xD;
rFrom = from p in flatList&lt;br&gt;&#xD;
orderby p.ParentId&lt;br&gt;&#xD;
select p;&lt;br&gt;&lt;br&gt;&#xD;
ParentChildDto prev = null;&lt;br&gt;&#xD;
var to = new List&amp;lt;Parent&amp;gt;( );&lt;br&gt;&#xD;
foreach( var dto in rFrom )&lt;br&gt;&#xD;
{&lt;br&gt;&#xD;
if(prev == null || prev.ParentId != dto.ParentId)&lt;br&gt;&#xD;
{&lt;br&gt;&#xD;
prev = new Parent&lt;br&gt;&#xD;
{&lt;br&gt;&#xD;
Id = dto.ParentId,&lt;br&gt;&#xD;
FullName = dto.Name&lt;br&gt;&#xD;
};&lt;br&gt;&#xD;
to.Add(prev);&lt;br&gt;&#xD;
prev.AllegedChildren = new List&amp;lt;AllegedChild&amp;gt;();&lt;br&gt;&#xD;
}&lt;br&gt;&#xD;
if(dto.ChildId != null)&lt;br&gt;&#xD;
prev.AllegedChildren.Add(new AllegedChild&lt;br&gt;&#xD;
{&lt;br&gt;&#xD;
Id = dto.ChildId,&lt;br&gt;&#xD;
FullName = dto.Name&lt;br&gt;&#xD;
});&lt;br&gt;&#xD;
}&lt;br&gt;&#xD;
return to;&lt;br&gt;&#xD;
}&lt;br&gt;&lt;br&gt;&lt;/pre&gt;&#xD;
        &lt;p&gt;&#xD;
While this works, it looks a little too old-school what with the funky indentation&#xD;
and the use of a "previous" placeholder. But try as I might, I can't think of another&#xD;
solution that would be cleaner or more maintainable. There's a chance I may be too&#xD;
"close" to the problem though.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Honorary Hillbilly Status awaits the person who provides an answer deemed worthy of&#xD;
the domain upon which this example is based. Answers must assume a cordial tone and&#xD;
work within the context outlined. Ones that do not (hint: These will be the answers&#xD;
that take the form "Why are you doing XXXX in the first place?" or one of its variations)&#xD;
will be summarily dismissed.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Advancefully Grateful&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=e780ad3a-98fc-468f-ad60-8e3702e33578"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=jn0DI_PWgtc:0qu_IGYGFuQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=jn0DI_PWgtc:0qu_IGYGFuQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=jn0DI_PWgtc:0qu_IGYGFuQ:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=jn0DI_PWgtc:0qu_IGYGFuQ:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=jn0DI_PWgtc:0qu_IGYGFuQ:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/jn0DI_PWgtc" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,e780ad3a-98fc-468f-ad60-8e3702e33578.aspx</comments>
      <category>.NET General</category>
      <category>Linq</category>
    <feedburner:origLink>http://kyle.baley.org/UnflatteningAListOrHowToAskHowTo.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://kyle.baley.org/Trackback.aspx?guid=4e945a10-9d8b-4771-b775-01a269e3c9e6</trackback:ping>
      <pingback:server>http://kyle.baley.org/pingback.aspx</pingback:server>
      <pingback:target>http://kyle.baley.org/PermaLink,guid,4e945a10-9d8b-4771-b775-01a269e3c9e6.aspx</pingback:target>
      <dc:creator>The Coding Hillbilly</dc:creator>
      <wfw:comment>http://kyle.baley.org/CommentView,guid,4e945a10-9d8b-4771-b775-01a269e3c9e6.aspx</wfw:comment>
      <wfw:commentRss>http://kyle.baley.org/SyndicationService.asmx/GetEntryCommentsRss?guid=4e945a10-9d8b-4771-b775-01a269e3c9e6</wfw:commentRss>
      
      <title>Fluent Sharp NHibernate Persistence Configuration, or &amp;ldquo;How to build credibility through OSS name dropping&amp;rdquo;</title>
      <guid isPermaLink="false">http://kyle.baley.org/PermaLink,guid,4e945a10-9d8b-4771-b775-01a269e3c9e6.aspx</guid>
      <link>http://feedproxy.google.com/~r/TheCodingHillbilly/~3/5Kwqo-XEsFM/FluentSharpNHibernatePersistenceConfigurationOrLdquoHowToBuildCredibilityThroughOSSNameDroppingrdquo.aspx</link>
      <pubDate>Mon, 27 Jul 2009 18:58:43 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;em&gt;For those of you skimming your RSS reader, I'll help you filter because I suspect&#xD;
my target audience is narrow with this one. This post deals with using the Fluent&#xD;
NHibernate IPersistenceConfigurer with Sharp Architecture.&lt;/em&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The hillbilly is a-codin’ agin! And back with Sharp Architecture which I had all but&#xD;
abandoned in favour of Repeaters and ItemCommands and various other monsters used&#xD;
to frighten young ASP.NET developers. (“Eat all your vegetables, Johnny, or tonight,&#xD;
when you’re fast asleep, THE VIEWSTATE OGRE WILL EXPAND INSIDE YOUR CLOSET UNTIL IT&#xD;
BLOWS UP ALL YOUR BROWSERS!!!”). Ah, it’s good to back in the realm of geek jokes&#xD;
that will surely embarrass my children at some future date…&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Much has happened in the Sharp Architecture world since I last visited. And to Fluent&#xD;
NHibernate, of which Sharp takes much advantage. It is now possible to work with NHibernate&#xD;
entirely without XML through the magic of fluent interfaces. Something that appeals&#xD;
to me aesthetically though it’s not a position I’ll defend to the death, or even to&#xD;
the slightly bruised.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Typically, NHibernate can be configured as follows:&#xD;
&lt;/p&gt;&#xD;
        &lt;pre class="c-sharp" name="code"&gt;var config = new Configuration( );&#xD;
config.Configure( pathToNHConfigFile );&#xD;
var sessionFactory = config.BuildSessionFactory();&lt;/pre&gt;&#xD;
        &lt;p&gt;&#xD;
Note that the parameter to Configure is optional. It appears that if one isn’t provided,&#xD;
it will default to looking for a file called NHibernate.config.xml. Though judging&#xD;
by how quickly things are changing, that may not be true by the time I click Publish.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The alternative with Fluent NHibernate is as follows:&#xD;
&lt;/p&gt;&#xD;
        &lt;pre class="c-sharp" name="code"&gt;var config = Fluently.Configure( )&#xD;
    .Database( MsSqlConfiguration.MsSql2005&#xD;
        .ConnectionString( c =&amp;gt; c.FromConnectionStringWithKey("mainConnection") )&#xD;
        .ShowSql( )&#xD;
        .ProxyFactoryFactory( "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" )&#xD;
    );&#xD;
var sessionFactory = config.BuildSessionFactory( );&lt;/pre&gt;&#xD;
        &lt;p&gt;&#xD;
In this case, you don’t even need an NHibernate Configuration object. Fluent NH looks&#xD;
to be doing all the work behind the scenes. All in all, it’s pretty clean and clear,&#xD;
save for that ProxyFactoryFactory call which may make sense to someone who has been&#xD;
actually following NH development. Personally, it required much BinGoogling to figure&#xD;
out that I even needed it.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
It’s possible to get lost in the options though. Fluently.Configure( ) takes an optional&#xD;
NHibernate Configuration object, which presumably could be configured via a config&#xD;
file. And you can add mappings to the NHibernate Configuration *and* the Fluent NH&#xD;
Configuration. It’s not mind-bogglingly circular but it does add an element of fun&#xD;
when you’re prone to just bang away without putting any thought into it.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This is where I segue back to SharpArchitecture. Sharp has supported Fluent NH for&#xD;
a while now with the class mappings. It also provides a nice interface for easily&#xD;
configuring NHibernate through some overloaded Init methods. But none of them supported&#xD;
the Fluent NH configuration API, likely because it’s relatively new.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
So at some point, another overload was created that took a Fluent NH IPersistenceConfigurer&#xD;
object, which contains the details about the NH configuration (e.g., the MsSqlConfiguration&#xD;
object above). However, it doesn’t account for situations where you provide an IPersistenceConfigurer&#xD;
but no config file. That is, the config file was still required even though you don’t&#xD;
need it.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
A patch is under evaluation to fix this so that something like the following will&#xD;
soon be possible:&#xD;
&lt;/p&gt;&#xD;
        &lt;pre class="c-sharp" name="code"&gt;var configuration = MsSqlConfiguration.MsSql2005&#xD;
    .AdoNetBatchSize(500)&#xD;
    .ShowSql()&#xD;
    .ConnectionString(c =&amp;gt; c.FromConnectionStringWithKey("main"))&#xD;
    .ProxyFactoryFactory("NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle");&#xD;
NHibernateSession.Init(webSessionStorage,&#xD;
    new string[] { Server.MapPath("~/bin/TingsForSale.Data.dll") },&#xD;
    new AutoPersistenceModelGenerator().Generate(),&#xD;
    null, null, null, configuration);&lt;/pre&gt;&#xD;
        &lt;p&gt;&#xD;
Until then, the only way to use the IPersistenceConfigurer aspect of Sharp Architecture&#xD;
is to either: a) provide a dummy config file, or b) mimic the code in NHibernateSession.Init&#xD;
like so: &#xD;
&lt;/p&gt;&#xD;
        &lt;pre class="c-sharp" name="code"&gt;var configuration = MsSqlConfiguration.MsSql2005&#xD;
    .AdoNetBatchSize(500)&#xD;
    .ShowSql()&#xD;
    .ConnectionString(c =&amp;gt; c.FromConnectionStringWithKey("main"))&#xD;
    .ProxyFactoryFactory("NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle");&#xD;
&#xD;
var fluentConfiguration = Fluently.Configure()&#xD;
    .Database(configuration)&#xD;
    .Mappings(m =&amp;gt;&#xD;
    {&#xD;
        m.AutoMappings.Add(new AutoPersistenceModelGenerator().Generate());&#xD;
        m.FluentMappings.AddFromAssemblyOf&lt;autopersistencemodelgenerator&gt;&#xD;
(); m.HbmMappings.AddFromAssemblyOf&lt;autopersistencemodelgenerator&gt;&#xD;
(); }); var nhConfiguration = fluentConfiguration.BuildConfiguration(); var validationEngine&#xD;
= new ValidatorEngine(); validationEngine.Configure(); ValidatorInitializer.Initialize(nhConfiguration,&#xD;
validationEngine); var sessionFactory = nhConfiguration.BuildSessionFactory(); NHibernateSession.SessionFactories.Add(&#xD;
webSessionStorage.FactoryKey, sessionFactory); NHibernateSession.Storages.Add(webSessionStorage.FactoryKey,&#xD;
webSessionStorage);&#xD;
&lt;/autopersistencemodelgenerator&gt;&lt;/autopersistencemodelgenerator&gt;&lt;/pre&gt;&#xD;
        &lt;p&gt;&#xD;
I'm hoping we can clean up the NHibernateSession.Init method somewhat because calling&#xD;
it with all those nulls looks mighty sketchy. But since Sharp Architecture recently&#xD;
came out with an official 1.0 version, I'm hesitant to start mucking with public interfaces.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Kyle the Private&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://kyle.baley.org/aggbug.ashx?id=4e945a10-9d8b-4771-b775-01a269e3c9e6"&gt;&lt;/img&gt;&#xD;
      &lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=5Kwqo-XEsFM:woTE0Xrq6A4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=5Kwqo-XEsFM:woTE0Xrq6A4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=5Kwqo-XEsFM:woTE0Xrq6A4:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?i=5Kwqo-XEsFM:woTE0Xrq6A4:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheCodingHillbilly?a=5Kwqo-XEsFM:woTE0Xrq6A4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheCodingHillbilly?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheCodingHillbilly/~4/5Kwqo-XEsFM" height="1" width="1"/&gt;</description>
      <comments>http://kyle.baley.org/CommentView,guid,4e945a10-9d8b-4771-b775-01a269e3c9e6.aspx</comments>
      <category>ASP.NET MVC</category>
      <category>NHibernate</category>
      <category>S#arp Architecture</category>
    <feedburner:origLink>http://kyle.baley.org/FluentSharpNHibernatePersistenceConfigurationOrLdquoHowToBuildCredibilityThroughOSSNameDroppingrdquo.aspx</feedburner:origLink></item>
  </channel>
</rss>
