tag:blogger.com,1999:blog-70452711758099233142024-02-25T23:01:05.470-08:00Steely Eyed ViewAnonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-7045271175809923314.post-27657464922225208622011-10-24T19:45:00.000-07:002011-10-24T19:45:45.571-07:00The Danger of Extension Methods<div class="MsoNormal">Today I came across something with extension methods that can cause code to break.<span> </span>If an extension method’s signature is equivalent to an actual method on the class or interface the extension method will not be called.<span> </span>For example let say I have the following classes:</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">Foo</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: blue;">public</span> <span style="color: blue;">object</span> FindItem(<span style="color: blue;">int</span> id)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: green;">//Some implimentation</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">FooExtensions</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: blue;">public</span> <span style="color: blue;">object</span> FindItem(<span style="color: blue;">this</span> <span style="color: #2b91af;">Foo</span> foo, <span style="color: blue;">int</span> id)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: green;">//Some slightly different implementation.</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">The <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">FindItem </span>in <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">FooExtensions </span>will never be called unless you call it as <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">FooExtensions.FindItem(foo, id);.</span><span> </span>In general this is not a horrible problem as you should avoid naming extension methods the same as an existing method.<span> </span>The problem comes in if someone extends or modifies a class so that the extension method was hidden.<span> </span>I discovered this the hard way.<span> </span>I had a class setup that looked like:</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">Foo</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: blue;">public</span> <span style="color: blue;">object</span> GetItem(<span style="color: blue;">int</span> id)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: green;">//Some implimentation</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">FooExtensions</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span> </span><span style="color: blue;">public</span> <span style="color: blue;">object</span> FindItem(<span style="color: blue;">this</span> <span style="color: #2b91af;">Foo</span> foo, <span style="color: blue;">int</span> id)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span><span style="color: green;">//Some slightly different implementation.</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><span> </span>}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">GetItem and FindItem had subtly different behavior in how they returned a value.<span> </span>In 90% of the cases the two methods behaved the same.<span> </span>However, there was one case where they didn’t.<span> </span>During a refactor of some code I was trying to unify the language in the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Foo </span>interface and renamed <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GetItem </span>to be <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">FindItem</span>.<span> </span>I didn’t realize that there was an extension method elsewhere in the code that this change would hide.<span> </span></div><div class="MsoNormal">Inevitably, this change broke in the one case where the two methods did not behave in the same manner.<span> </span>However, it was unclear as to why the code broke.<span> </span>I spent a good hour looking at the broken code and could not determine why it ever worked.<span> </span>Since the extension method is hidden by the class’s method of the same name it does not appear when trying to find references.<span> </span>After searching for a solution to no avail, I made a change to the code call to what used to be the extension method version of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">FindItem</span>.<span> </span>Interestingly, this made the code more efficient.<span> </span>It was only a month later i.e. today when I came across the extension method and found no references to it that I realized what had happened.<span> </span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">This experience has led me to some thoughts about good coding practices to avoid this issue.</div><div class="MsoNormal"></div><ul><li><span class="Apple-style-span" style="font-family: inherit;">Make sure all your extension methods have unit tests associated with them.</span><span style="font-family: inherit;"> </span><span class="Apple-style-span" style="font-family: inherit;">This issue would have been spotted in a unit test for the extension method if a test for it had existed.</span><span style="font-family: inherit;"> </span><span class="Apple-style-span" style="font-family: inherit;">My project </span>doesn't<span class="Apple-style-span" style="font-family: inherit;"> use a TDD approach and we don’t have full coverage so this error was not caught at this level.</span><span style="font-family: inherit;"> </span><span class="Apple-style-span" style="font-family: inherit;">A good unit test would have caught the case that caused the error.</span><span style="font-family: inherit;"> </span><span class="Apple-style-span" style="font-family: inherit;">This is the most straightforward and safest way to prevent the error.</span></li>
<li><span class="Apple-style-span" style="font-family: inherit;">Collect the extension methods in a place that makes them easy to find.</span><span style="font-family: inherit;"> </span><span class="Apple-style-span" style="font-family: inherit;">They probably should be within their own namespace.</span><span style="font-family: inherit;"> </span><span class="Apple-style-span" style="font-family: inherit;">Part of the reason this error </span>wasn't<span class="Apple-style-span" style="font-family: inherit;"> caught was that the offending extension method was in a general namespace that was referenced for other reasons.</span><span style="font-family: inherit;"> </span><span class="Apple-style-span" style="font-family: inherit;">If a namespace suddenly was no longer needed, this would have been a clue about the cause of the problem.</span></li>
<li><span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"><span class="Apple-style-span" style="font-family: inherit;">Be judicious with the use of extension methods. The </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">FindItem </span><span class="Apple-style-span" style="font-family: inherit;">method should have been part of </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Foo</span><span class="Apple-style-span" style="font-family: inherit;">. It was a mistake to not put it there in the first place. Extension methods are really tempting for people who come from a procedural programming background. However, they should only be used as a mechanism to extend functionality when the code cannot be extended otherwise. They should not be used as way of not adding a method to an object or just providing a method that should be a static method to the class.</span></span></li>
</ul>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com14tag:blogger.com,1999:blog-7045271175809923314.post-2677637849492878002011-10-19T18:26:00.000-07:002011-10-20T05:16:57.500-07:00My Experience Getting Started With Ruby on Rails<div class="MsoNormal"><br />
<div class="MsoNormal">I have been meaning to learn to Ruby on Rails for a while and finally made the decision to start a project. The following was my experience trying to setup Rails and getting started on building a first application. Included are my thoughts as I went along. Overall I am impressed with Ruby on Rails. In reality it is simple to get something set-up quickly. However, some of my experience has made me question how easy some of the more complicated aspects will be. Those will be subjects of other blogs. This should not be taken as a how-to on setting up Ruby on Rails. There are many excellent tutorials about that out there and this isn't one of them. I am in no way trying to write a tutorial. Instead, I want to share my experience with setting it up. This has a twofold purpose. I found the processes to be enjoyable and wanted to share my joy in doing this. The other was that I had some struggles as I went along. My hope is that if someone encounters the same or similar errors, my experience might be helpful to them. I've linked to most of the pages I've used in hope of directing people to the resources I found useful.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Friday 10:30 PM: </b>I decided to get started. First step go to the <a href="http://www.ruby-lang.org/en/">Ruby page</a>. I don’t know Ruby at all so I take a quick look at the <a href="http://www.ruby-lang.org/en/documentation/">documentation page</a>. I select a link for Ruby from Other Languages and select the <a href="http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/to-ruby-from-java/">From Java</a> page, since it is the language in the list I am most familiar with. I take a quick skim of the document. It doesn’t seem too intense. Some things I am aware of already like the concept of “everything is an object.” Others I am not. It is a good quick overview of Ruby in the abstract. At this point I also go to the download page. I read through the page and find the <a href="http://rubyforge.org/frs/?group_id=167">RubyInstaller for Windows page</a> and download the latest version (1.9.2-p290). After it completes the download I run the installer. While it installs I go to the <a href="http://rubyonrails.org/">Ruby on Rails</a> site. I then get to the <a href="http://rubyonrails.org/download">Ruby Downloads</a> page which has a clear set of instructions for getting started with Rails. I have already performed the first step of installing Ruby itself. Next up is RubyGems. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Friday 10:40 PM:</b> I follow the link to get to the <a href="http://rubyforge.org/frs/?group_id=126">RubyGems</a> download page. I download the latest version (1.8.10). I then unzip it to a folder next to my Ruby install and using the command line run <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">ruby setup.rb</span>. Installation proceeds quickly and now I can use gems. The gem concept seems really nice as it allows you to easily install new components from the command line. It all is working well so far.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Friday 10:50 PM: </b>Now on to Rails. I download version 2.2.3 from the <a href="http://rubyforge.org/frs/?group_id=307">download page</a>. This would be my first misstep of the night. I really was not paying close attention at this point and just figured that what was on the page was the most recent. After all, the link on the Rails home page had said try Rails 3. That link had sent me to the download page with the instructions which had sent me to this page. All this I didn’t realize at the time. I also didn’t understand how gems worked at this point. I didn’t even need to download the package. All I had to do was in the command line type <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">gems install rails</span></span></span>. I realize my mistake and I run the command prompt. Rails installs. I’ve decided to call my test application “Dolphin”, just as a simple code name. So now I create my source directory by typing <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">rails new Dolphin</span></span></span> in a folder where I keep my source code.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Friday 10:55 PM: </b>At this point I decide I need more directed help and find a good walk through setup guide called <a href="http://guides.rubyonrails.org/getting_started.html">Getting Started with Rails</a>. This is good because it walks through things in more detail and I want to understand why things work, not just that they do. This also points out the <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace; font-size: x-small;">database.yml</span> file. <b></b></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Friday 11:10 PM: </b>Reading the “getting started guide” has made me want to use MySQL instead of the built-in SQLite instance. I change the configuration then go to install MySQL. To do this I figure the easiest way to do this is install a <a href="http://www.apachefriends.org/en/xampp.html">XAMPP</a> stack. This way I get PHPMyAdmin to manage the database. I <a href="http://www.apachefriends.org/en/xampp-windows.html">download the latest version</a> (1.7.7) and install. After the installation is complete Apache won’t start because I have IIS running on port 80 for some other development. I change Apache to run on port 8000 because that’s much quicker and easier than turning off IIS. I get this up and running and decide to call it quits for the night.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 9:30 AM: </b>For some reason I am having trouble with getting the rails instance setup. Folders aren’t being created in the way I would expect. I go into the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin</span></span> folder and type <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">rake</span></span> <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">db:create</span></span>. I get an error when I do this telling me that there is no such file to load. I go into my explorer view to look at the folders and realize the problem. Nothing is going into my <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin</span></span> folder and a folder called new is being created instead. I think maybe I need to be in the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin</span></span> folder, but the new folder then appears in there. I also realize at this point that all the files I’m expecting to be in my <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin</span></span> folder are in my new folder so I omit the new and it seems to create what I want. I then do the database create rake again and get a new error. This time around I get a different error telling me: <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">NameError (undefined method `path' for class `ActionController::UploadedStringIO').</span></span></span> I use Google to find me what my problem is. After some looking <a href="http://www.genmaint.com/error-undefined-method-path-on-script-generate.html">this post</a> clues me in. I have Rails 2.2.3 installed but I am using Ruby 1.9.2. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 9:40 AM:</b> No reason not to start with Rails 3 so I go to figure out how to update to Rails 3. After some searching around and following the same path multiple times I find the Rails 3 beta page which tells me I can install it by typing <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">gems install rails –pre</span></span></span>. It works like a charm and installs. I now go back and type <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">db:create</span></span> and it fails again. However, it is a different failure this time. This time the error message said: <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">r<span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">ake aborted! uninitialized constant Rake::DSL</span></span></span>. Back to Google for this one. <a href="http://stackoverflow.com/questions/6268518/uninitialized-constant-rakedsl-in-ruby-gem">This proved to be an easy fix</a>. I just needed to change the Rakefile to include <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">require 'rake/dsl_definition'</span>.</span></span></div><div class="MsoNormal"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><br />
</span></span></div><div class="MsoNormal"><b>Saturday 9:55 AM: </b>At this point I was sure that when I typed <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace; font-size: x-small;">db:create</span> it would all go smoothly. Unfortunately, the major headache of the day was just beginning. When I ran the command again I got another error that looked similar to the previous one. This time the error was <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">uninitialized constant mysql2</span></span>. A Google search resulted in that I needed to install the <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace; font-size: x-small;">mysql2 </span>gem. This seemed easy enough. Just type<span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"> <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">gem install mysql2</span></span></span> and all should be good. But, no, another error. Fortunately, this time the error told me what to do. The error even provided me a helpful link to the <a href="http://rubyinstaller.org/downloads">ruby installer download page</a>. The problem was I needed to install the Development Kit. Finally, a logical error that had a logical resolution. I followed the <a href="https://github.com/oneclick/rubyinstaller/wiki/Development-Kit">instructions</a> for installing. These were some of the best instructions I’ve found for installing software.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 10:10 AM: </b>At this point I think I am home free. I go try to install mysql2 again. This time I get another. I got the following Error: <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"> </span><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">Failed to build gem native extension</span>. </span></span>Again back to Google to find some help for this one. One of the suggestions pointed me to use <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">gem install mysql -- --with-mysql-lib=/usr/lib/mysql/lib</span></span>. This made sense. My MySQL instance was installed inside XAMPP so of course I’d have to specify its location to the gem installer. This was correct, however I did not understand the command line syntax correctly lead me down another false path. I thought the first two<span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"> <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">--</span></span> </span>were unimportant. In my mind I was interpreting them as a filler for other switches. So I typed <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace; font-size: x-small;">gem install </span><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace; font-size: x-small;">--with-mysql-lib=C:\Programming\Tools\xampp\myphp</span>. Every time I tried to run this because it kept saying that “C:\” is not a valid path. At this point I was very confused. I tried using only a relative path. When I used the relative path the command ran successfully. I figured I was home free. However, when I tried the <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace; font-size: x-small;">db:create</span> command again, I got the same failure. Back to the drawing board, well back to Google to search for more help. I found lots of results and lots of different suggestions. None of which worked. It is at this point I realized there are probably a lot of Apple users who use Rails. There was a surprising number of results related to fixing the problem in OS X. I had to resort to searching for a Windows specific fix.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 11:00 AM: </b>After an over half an hour of not making any headway I decide to take a break and get ready to watch the Penn State game. I figure I’ll return to this later with a fresh mind as I was just beating my head into the wall.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 6:00 PM: </b>After watching a dull Penn State victory and some other chores it was time to return to trying to get this instance up and running. I returned to some of my earlier searches and finally determined that my previous attempt had failed not because the instructions were wrong but that I was implementing them wrong. I looked in the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">mysql</span></span> folder and saw that I had created a <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace; font-size: x-small;">with<span class="Code"><span style="line-height: 115%;">\mysql\(and lots more nested folders) </span></span></span>directory. I realized my mistake from earlier. By omitting the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">--</span></span> in the previous command I change how that command functioned and it took the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">–with-mysql-</span></span></span> as a folder to create instead of an option to the command. I ran the command with the<span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"> <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">-- </span></span></span>and it seemed to succeed. I ran the rake command again and I got the failure once again. It said “<span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">rake aborted! uninitialized constant mysql2.</span></span></span>” Same problem. All the error handling I found said I needed to add the mysql2 constant to the gem file. I mistook this as something I had to do in the ruby install and spent a fruitless half hour trying to find the gem file in the Ruby and the Ruby on Rails folders. It is only much later that I realized the gem file was contained within my <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin </span></span></span>folder. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 6:50 PM:</b> After unsuccessfully trying to find the gem file in a location that did not exist I went looking for more help and I found <a href="https://rails.lighthouseapp.com/projects/8994/tickets/5502-rake-dbcreate-problem-in-rails3-with-mysql2">this page</a>. This was a bug report and at the bottom of it I found what I thought was helpful advice. It said “It seems like a MYSQL Version Problem. Try uninstalling MySQL 5.5 if you have this version and install MYSQL 5.1.” This seemed like sage advice, but was annoying because it meant determining which version of XAMPP had MySQL 5.1 included. I then had to uninstall my current XAMPP version and reinstall that. I made some stupid mistakes in doing this (I reinstalled my same version and installed the lite version. I eventually got version 1.7.3 installed. This took a while because I installed and uninstalled a couple times and go distracted looking at parts to build myself a new computer. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 8:00 PM: </b>I finally was setup to go again. After installing the new XAMPP instance I reinstalled the Ruby gem for mysql2 and thought I was home free. However, it failed again. I was really frustrated. It was at this point I decided to figure out the gem file problem from before. After some more searching online and looking in my folders I saw what I was missing. There in my <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin</span></span> </span>folder I found a file called <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">Gemfile</span></span></span>. It could not have been more obvious. All that pain was because I was overlooking something simple. Since I had done nothing useful in the <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin</span></span> </span>folder I deleted it and re-ran the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">rails new Dolphin</span></span></span> command in hopes that it would update the Gemfile.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 8:50 PM: </b>I tried running the rake again and I had the DSL problem from before. I looked up how to solve that problem again. I fixed it the same way as before. Then I typed <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">rake db:create</span></span></span>. Success! Well, sort of. At this point I had forgotten that by deleting the whole <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">Dolphin</span></span> </span>directory I had deleted my yml file. I thought I was using the MySQL instance but I was actually using the SQLite. A fact I only realized when I looked at the database in PHPMyAdmin and nothing had been added. At this point I was just excited to play with Ruby and Rails. I didn’t feel like going through any more hassle. Using MySQL would have to wait for another day. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 9:10 PM: </b>At this point I figured I’d be writing some Ruby code soon so I wanted an IDE to do that in. I figured since I was a novice at the syntax this would be a good idea. I went searching for what IDE to use. I first thought I’d use NetBeans because I had seen Ruby support in it before. However, this thought was dashed because I found <a href="http://netbeans.org/community/news/show/1507.html">this announcement</a>. Apparently Ruby was not being supported by NetBeans anymore. I searched online for some recommendations. I eventually decided on <a href="http://www.aptana.com/">Aptana Studio</a> (which is built on top of Eclipse) based upon some recommendations and my familiarity with Eclipse. I got that downloaded and extracted. This was wasted time really because I didn't wind up using it at all</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 9:20 PM: </b>I now returned to where I was the night before going through the walk through. My next step was to just start the server. I typed <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">rails server</span></span></span> to get it going. This was awesome; it seemed to start with no issues. Way simpler than getting a Java project to deploy. I went to <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">http://localhost:3000</span></span></span> (the port it starts on by default) and the default start-up page was there. It was good to have something work right off the bat. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 9:23 PM: </b>Back in the console I shut down the server using Ctrl + C. The next step was to generate some content. So I used the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">rails generate controller home index</span></span></span> command as instructed to in the walk through. This succeeded with no issues. The tutorial told me then to go to the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">app/views/home/index.html.erb</span></span></span> file and change the contents. This I did. I also deleted the default index page by removing the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">public/index.html</span></span></span> file and changed the routing by uncommenting the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">root :to => "welcome#index"</span> </span></span>line in the<span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"> <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">config/routes.rb</span>. </span></span></div><div class="MsoNormal"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><br />
</span></span></div><div class="MsoNormal"><b>Saturday 9:38 PM: </b>I once again restarted the server and went to the default page, hopeful to see the HTML I had entered a minute ago. Instead I got an error on the page that said “<span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">uninitialized constant WelcomeController</span></span>.</span>” Another road block. I search for an answer for a minute before I notice something. In the tutorial I am reading it says to uncomment <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">root :to => “home#index”</span></span></span> line but my <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">routes.rb</span></span> actually has <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">root :to=> “welcome#index”</span></span></span> for the line. I change <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">welcome</span></span> </span>to <span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;"><span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;">home</span></span> </span>and reload the page. Viola, it works, showing the HTML I had put into the template. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>Saturday 9:55:</b> I follow along with the tutorial without any more incident. I gets me up and running with a simple module really quickly. It creates a creation page, a listing page, and an edit page by just running the <span class="Code"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-family: "Times New Roman"; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-bidi;"><span class="Apple-style-span" style="font-family: "Courier New", Courier, monospace;">rails generate scaffold Post …</span></span></span> command. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal">I am going to end the discussion of my experience at this point as the rest of what I did was rather vanilla. Overall I had a positive first experience with Ruby and Rails. If I hadn’t detoured to try to use MySQL it would probably have taken no more than an hour to go from nothing to an application that can enter, retrieve, and edit data. There is a lot more for me to explore and I am excited about exploring it. I will post more blog entries as I explore more. </div></div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com6tag:blogger.com,1999:blog-7045271175809923314.post-3953789020813482682010-12-07T19:05:00.000-08:002010-12-07T19:05:47.488-08:00HashMap of a HashMap of a HashMap Problem -- Part 4 - A Way To Correct The Problem<div class="MsoNormal">Previously we have seen how collections can be used to circumvent the type system. They can be thought of creating classes without actually creating classes. This can be useful when you have simple relationships you want to store, but confusing as you add more complicated relationships. They lead to maintainability nightmares where even the original author does not understand what is occurring. The code is mucked up with nested data structures both in the definition of the relationships and the use of them. Now we’ll see how to correct the problem.</div><div class="MsoNormal">The way to correct the problem is not revolutionary. In fact, it is not something that I used to think I had to explain. It was only after I saw multiple developers create the HashMap of a HashMap of a HashMap problem and explained what they should have done that I realized not everyone saw it as intuitive. The solution is simply applying good object oriented principles. Let us return to our Person class we created in Part 2 (for now we will keep the birthday out of the relationship):</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Person</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> Name { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> Nicknames { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">In Part 3 we added complexity that the name was actually just a first name and that we wanted to tie last name to the first name and the list of nicknames. Let us add this information to our <span style="font-family: 'Courier New';">Person</span> class:</div><br />
<div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Person</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> FirstName { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> LastName { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> Nicknames { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We have now defined a class that encapsulated the information contained in our <span style="font-family: Consolas; font-size: 9.5pt; line-height: 115%;">LastNameToFirstNameToNicknameMap</span> in Part 3 into an object. If we have a list of <span style="font-family: 'Courier New';">Persons</span> we have the same information as we did in our complex nested properties. However, we’ve lost some of the ability to quickly retrieve values based upon name values. We have to look through the list of persons for a match. There are a couple ways we can approach the problem at this point, depending upon how we want to expose and deal with our data. The following is just one way that this can be handled. Let’s call a collection of people who share a last name a Family. A family class would on a basic level look like this:</div><br />
<div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Family</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> LastName { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Person</span>> People { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"> I’m purposefully omitting the constructor and methods needed for management of the family for simplicity. Let us also think about the other layer of data we wanted to have which was nationalities and add that data to our objects as well. Our Family and Person class would look as follows:</div><br />
<div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Person</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> FirstName { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> LastName { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> Nicknames { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> Nationality { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Family</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> Nationality { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> LastName { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Person</span>> People { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">You’ll notice that Nationality and Nickname is duplicated between the two objects. This is purposeful on my part. This could be handled in other ways, like as a Person could have a reference to his family. This makes sense in our contrived example, but in practice, I find the way this is structured to be more practical. In reality, I often want to create the type of object a Person is our example of without knowing what family it will belong to at creation time. However, I know the properties like LastName and Nationality at creation time. What I mean is that I want to construct families from people not create families and then add people to it. It is a subtle difference, but is the general case where I’ve seen the HashMap of a HashMap of a HashMap problem occur. You of course should write the data structure that is most appropriate for your situation.</div><div class="MsoNormal">Ultimately, I need some sort of top-level object that will provide be access to the values. I could just use a list of Families and have some outside object manage the adding and removal of items, but that breaks the object-oriented approach we are going for. What we really want to do is encapsulate the management logic into a class and provide convenience methods for access and manipulation. Let’s call our top level object Families. I am going to construct a class with some basic features for creating our constructs based upon a person. Let me preface this by saying it is meant to illustrate the structure, not be a fully functioning example:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Families</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> Private class to encapsulate the logic connecting a last</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> name to a family</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">LastNameFamilyMap</span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Family</span>> _familyMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> LastNameFamilyMap()<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _familyMap = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Family</span>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> AddFamily(<span style="color: #2b91af;">Family</span> family)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _familyMap.Add(family.LastName, family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> RemoveFamily(<span style="color: #2b91af;">Family</span> family)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _familyMap.Remove(family.LastName);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">Family</span> GetFamily(<span style="color: blue;">string</span> lastName)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Family</span> family;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (_familyMap.TryGetValue(lastName, <span style="color: blue;">out</span> family))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> family;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> <span style="color: blue;">null</span>;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> Private class used to encapsulate the nationality</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> to families relatonship.</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">NationalityFamilyMap</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>>> _nationalitiesToFamilies;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">LastNameFamilyMap</span>> _familyMappings;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> NationalityFamilyMap()<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _nationalitiesToFamilies = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> AddFamily(<span style="color: #2b91af;">Family</span> family)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>> families;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span>(!_nationalitiesToFamilies.TryGetValue(family.Nationality, <span style="color: blue;">out</span> families)){<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> families = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _nationalitiesToFamilies.Add(family.Nationality, families);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> families.Add(family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">LastNameFamilyMap</span> lastNameMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (!_familyMappings.TryGetValue(family.Nationality, <span style="color: blue;">out</span> lastNameMap))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> lastNameMap = <span style="color: blue;">new</span> <span style="color: #2b91af;">LastNameFamilyMap</span>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _familyMappings.Add(family.Nationality, lastNameMap);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> lastNameMap.AddFamily(family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> RemoveFamily(<span style="color: #2b91af;">Family</span> family)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>> families;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (_nationalitiesToFamilies.TryGetValue(family.Nationality, <span style="color: blue;">out</span> families))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> families.Remove(family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">LastNameFamilyMap</span> lastNameMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (_familyMappings.TryGetValue(family.Nationality, <span style="color: blue;">out</span> lastNameMap))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> lastNameMap.RemoveFamily(family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">Family</span>> GetFamilies(<span style="color: blue;">string</span> nationality)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>> families;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span>(_nationalitiesToFamilies.TryGetValue(nationality, <span style="color: blue;">out</span> families)){<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> families;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">Family</span> GetFamily(<span style="color: blue;">string</span> nationality, <span style="color: blue;">string</span> lastName)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">LastNameFamilyMap</span> lastNameMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (_familyMappings.TryGetValue(nationality, <span style="color: blue;">out</span> lastNameMap))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> lastNameMap.GetFamily(lastName);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> <span style="color: blue;">null</span>;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">Family</span> GetFamily(<span style="color: #2b91af;">Person</span> person)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> GetFamily(person.Nationality, person.LastName);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: #2b91af;">NationalityFamilyMap</span> _nationalityFamilyMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>> _families;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Person</span>> _people;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> Families()<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _nationalityFamilyMap = <span style="color: blue;">new</span> <span style="color: #2b91af;">NationalityFamilyMap</span>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _families = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Family</span>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _people = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Person</span>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">Family</span>> Families { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> _families; } }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">Person</span>> People { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> _people; } }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> Add(<span style="color: #2b91af;">Person</span> person)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Family</span> family = _nationalityFamilyMap.GetFamily(person);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (family == <span style="color: blue;">null</span>)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> family = <span style="color: blue;">new</span> <span style="color: #2b91af;">Family</span>(person);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _nationalityFamilyMap.AddFamily(family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _families.Add(family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">else</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> family.People.Add(person);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _people.Add(person);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">This may seem over whelming at first. I also apologize for the dearth of comments. This is just one way you can implement the management of the relationship we had in only collections at the end of Part 3. There is a lot more complexity in the code here than the basic collection structure we had, but it is all for good reason. What we are doing here is encapsulating the management into the object itself. We are using two private classes to abstract away the underlying collections. </div><div class="MsoNormal">The private classes may seem complex, but they are in reality quite simple. Their purpose it maintain specific relationships between objects and enable us to easily retrieve those relationships. Lets look at the <span style="font-family: 'Courier New';">LastNameFamilyMap</span> alone.</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"> ///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"><summary></span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> Private class to encapsulate the logic connecting a last</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> name to a family</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">LastNameFamilyMap</span>{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Family</span>> _familyMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> LastNameFamilyMap()<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _familyMap = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Family</span>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> AddFamily(<span style="color: #2b91af;">Family</span> family)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _familyMap.Add(family.LastName, family);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> RemoveFamily(<span style="color: #2b91af;">Family</span> family)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> _familyMap.Remove(family.LastName);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">Family</span> GetFamily(<span style="color: blue;">string</span> lastName)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Family</span> family;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (_familyMap.TryGetValue(lastName, <span style="color: blue;">out</span> family))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> family;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> <span style="color: blue;">null</span>;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We have specific methods to add, remove and add families. This gives us explicit control over changes to our structure. This is something we don’t get with straight collections. We’ve encapsulated the underlying dictionary into a structure so that if we want to keep track of additional information from our Family object we are able to easily. Our management points for changing this are only in the <span style="font-family: 'Courier New';">AddFamily</span> and <span style="font-family: 'Courier New';">RemoveFamily</span> methods of the class. This means we can easily provide a reverse lookup Dictionary, which would be useful if <span style="font-family: 'Courier New';">LastName</span> wasn’t part of the Family object (which in the real world might be the case). We also are sure that nobody can change our underlying collection without accessing it through our methods. </div><div class="MsoNormal">This is basic data encapsulation but it’s something that is not often done. I was working on a relationship like this just the other day. I had to allow the storage of a new type of relationship. If I had just had a HashMap of a HashMap of a HashMap I would have never been able to enforce the tracking constraints that I did. Let say I wanted to make it so only families with a last name that began with A were being tracked. This is an easy check to put into our Add method. Or I can make it so families with more than three members cannot be removed. The data encapsulation puts our logic into this one location and ensures that the rules are always followed.</div><div class="MsoNormal"> Looking at our private classes we could have substituted the <span style="font-family: 'Courier New';">LastNameFamilyMap</span> reference in <span style="font-family: 'Courier New';">NationalityFamilyMap</span> with just a straight Dictionary but then we’d be back to where we started with a Dictionary containing a Dictionary. In essence, this is what that relationship is, but we are using another object to indirect this relationship. All the complexity of dealing with the dictionary moves inside the object making additions and removals from it much simpler.</div><div class="MsoNormal">The same is the case for our <span style="font-family: 'Courier New';">NationalityFamilyMap</span>. Here we actually have two Dictionaries. One allows us to easily keep track of Families based upon nationality while the other provides a quick look-up for a Family based upon Nationality and <span style="font-family: 'Courier New';">LastName</span> of a Person. </div><div class="MsoNormal">Because of the sub-classes manages the adding a person to our collection is quite simple. We can easily look-up if that person’s family exists through our sub-class. If it does not exist, we can easily create a new one and add it to our internal collections and objects. The onus for the complicated logic needed to create add a new Person, including creating a new Family is on us as a developer of the management class, not the user of the data structure. Not included in the code are the accessors that the definition of this structure might require. We might want to get all the families of a nationality. This would involve simply adding a method to our Families class that looks like this:</div><br />
<div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">Family</span>> GetFamilesOfNationality(<span style="color: blue;">string</span> nationality)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;"> return</span><span style="font-family: Consolas; font-size: 9.5pt;"> _nationalityFamilyMap.GetFamilies(nationality);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">This is much simpler than what we would have had to write if we still had our collection only implementation from Part 3. The function that would then have looked like:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"> <span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>> GetFamilesOfNationality(<span style="color: blue;">string</span> nationality)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>> lastNameMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (NameMap.TryGetValue(nationality, <span style="color: blue;">out</span> lastNameMap))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> lastNameMap.Values;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>>();<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Underneath the hood, the code would look very similar but as far as readability goes, the version with the <span style="font-family: 'Courier New';">Family</span> class is much easier to read. The layering of objects also allows us to keep congruent sets of information to speed up retrieval when we want something other than a direct lookup. We keep a running list of families at very little cost. If we wanted to keep them sorted in some manner (add order or on some value) this would be easy as well.</div><div class="MsoNormal">Part of what makes this method of encapsulating values valuable is controlling access. We limit the access points through our add and remove methods. We therefore are able to add new backing collections that aid in our access easily. Since we have limited access points, object management only needs to be added in those specific points. The added complication in our object ultimately makes for a more elegant code that uses our management object. It is also more maintainable as the encapsulation pinpoints responsibilities within objects.</div><div class="MsoNormal">We could keep examining the structure in detail and analyze all of its facets, but I think this is sufficient for now. I would encourage you to try writing accessors to get values out of each structure and see which one you like using better. When writing accessors for the class structure feel free to add new collections to improve retrieval time and see how the code easily falls into place. </div><div class="MsoNormal">What I hope you have gotten out of the last series of posts is an understanding of the HashMap of HashMap of HashMap problem. I hope you see that in code it is an unwieldy structure to use. It is a way of circumventing object-oriented design. I hope I have given you at least one path on how you can transform that structure into classes. My hope is that in the future when you see nested collections you will question if that is really how you want the data to be contained. It is more work up front to create the classes to contain the data but in the end, you will save yourself headaches if you do write specialized classes to manage complex relationships. </div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com3tag:blogger.com,1999:blog-7045271175809923314.post-35033337892357183272010-12-01T16:12:00.002-08:002010-12-01T16:12:57.419-08:00HashMap of a HashMap of a HashMap Problem -- Part 3 - Seeing the Problem<div class="MsoNormal">Previously we looked at the need for meta-data and good naming when using collections to form associations. We also looked at how collections are used to circumvent typing. Now we are really going to see how this circumvention can get you into trouble and what my lead developer was actually talking about in his argument with the other developer.</div><div class="MsoNormal">Up to this point we’ve created properties for our mappings without a class to contain them, this has been very purposeful. Let’s ignore that we added the name to birthday mapping and assume we still just have name to nicknames that we want to map. Let’s say these names are only first names. Let’s say we want to map last names to a group of first names that match to a list of nicknames. That’s probably confusing to read as we have now chained three things together and that makes it hard to follow. A property for this sort of value structure, using only collections, would look like this:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>> NameMap { <span style="color: blue;">get</span>; }<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">I’ve gone back to the simple naming convention and lack of documentation on purpose to illustrate how I’ve seen similar relationships in code. If you were given only this property with no documentation and a name like NameMap what would you make of it? Would you have any idea where to begin? Quite simply, no. You’d have to start digging through the code to determine what all the values are for. Let’s be “kind” and add documentation and improved naming.</div><br />
<div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"><summary></span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> Gets a map of last names to a map of first names to nicknames for</span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> the person with that first name. The dictionary maps</span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> last names -> first names -> nicknames </span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"></summary><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>> LastNameToFirstNameToNicknameMap { <span style="color: blue;">get</span>; }<o:p></o:p></span></div></div><br />
<div class="MsoNormal"><br />
</div><div class="MsoNormal">If you can understand what that comment intends to communicate then congratulations. I’m going to be honest and tell you I spent five minutes trying to make a coherent sentence to describe the structure and believe I have failed miserably. The only way I could even remotely express what was being contained in the structure was to use the arrow notation at the end of the comment. That only gives me the very basic information. The fact that I was having trouble explaining the data structure should set off red flags that it is not a good data structure. Also, notice the ridiculous name I had to give the property in order to clarify its meaning. There are eight separate words in the name. It explains the object but I tend to get lost in the middle or reading it. Its way too long, even though it spells out our relationship. Again, this is another red flag.</div><div class="MsoNormal">We are now beginning to see the HashMap of a HashMap of a HashMap problem. We only have two levels of nesting with our HashMaps and we already are beginning to see that it is becoming unmanageable. </div><div class="MsoNormal">Let’s take it one step further and see how this gets even more complex. Say we want to add one more level of lookups to our data structure and map nationality to our previous structure. For simplicities sake I’m just going to consider everyone with the same last name shares a nationality and I am going to use a string for nationality. Obviously, this is not how the real world works and we’d probably create an enumeration for nationality. This example is contrived, but we’ll live with it because I’m attempting to illustrate a problem that occurs when you have nested data relationships. This is the important factor for our contrived example. If we want a property that returns our new relationships we would then have:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>>> NameMap { <span style="color: blue;">get</span>; }<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We now have a HashMap of a HashMap of a HashMap with a contained list thrown in for good measure. Good luck ever understanding what is going on here. The scary thing is I’ve come across such a data structure more than once in my career. It scares me that someone could look at a structure like this and not think that there was something wrong. I’m not going to even attempt to add the meta-data and transform the name. I encourage you to try to do so in a cogent manner. It is near impossible to write an explanation of what is being mapped here. Part of our lesson here is if you cannot explain the basic structure of a property in a sentence, it is probably too complex.</div><div class="MsoNormal">The structure also leads to complex access code with nested if-blocks just to get a value. Let’s assume we want to see if a nickname belongs to someone with a given nationality, last name, and first name. The code to do this would look something like:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">bool</span> HasNickname(<span style="color: blue;">string</span> nationality, <span style="color: blue;">string</span> lastName, <span style="color: blue;">string</span> firstName, <span style="color: blue;">string</span> nickname)<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>> lastNameMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>> firstNameMap;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> nicknames;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (NameMap.TryGetValue(nationality, <span style="color: blue;">out</span> lastNameMap))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (lastNameMap.TryGetValue(lastName, <span style="color: blue;">out</span> firstNameMap))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">if</span> (firstNameMap.TryGetValue(firstName, <span style="color: blue;">out</span> nicknames))<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> {<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> nicknames.Contains(nickname);<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">return</span> <span style="color: blue;">false</span>;<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">There are 3 nested ifs and three objects being created as outs that are collections themselves. The long and short of this being that even a simple boolean check becomes insanely complex. I even tried using LINQ to write a simplified version of this and I got myself lost in it. Point being is the end user has to write complex data accesses to use our structure. </div><div class="MsoNormal">The overarching point I’m trying to make is that if you have more than one level of nesting of collections you should re-evaluate how you are writing your code. You are relying on weak references to build your structure. Your code will be very hard to maintain. It is hard enough to try to explain what the structure is encapsulating. It is even harder to understand it without a priori knowledge. My general rule of thumb is that anything past our original nesting of a list in HashMap (Dictionary) is too much and should be rewritten. You are putting a large, unneeded burden on code that uses your data structure. </div><div class="MsoNormal">Next time we will see what we should do instead to fix/avoid the problem.</div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com2tag:blogger.com,1999:blog-7045271175809923314.post-3118559913091775732010-11-28T05:36:00.000-08:002010-11-28T05:36:28.929-08:00HashMap of a HashMap of a HashMap Problem -- Part 2 - Adding Complexity<div class="MsoNormal">In our previous part we started discussing how even basic collection usages require careful use of meta-data. Our example was simple but now we are going to begin to add some complexity to it. This complexity will begin to lead us down the path to the problem.</div><div class="MsoNormal"> Let us make some modifications to our example to add a little complexity. In all likely-hood, a person will have more than one nickname. We want to be able to retrieve all their nicknames based upon their name. Therefore, we modify our property to be as follows:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"><summary></span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> Gets a map of a user's name (the key) to their nicknames </span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> (the value) so we can look up their nicknames quickly</span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"></summary></span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>> NameToNicknamesMap { <span style="color: blue;">get</span>; }<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">This still is not horrible but it is more complex. We now have a nested collection that causes us some grief in writing code to access the values. This is not a big deal it just makes our code less clean. We still can easily understand it if the property is well documented.</div><div class="MsoNormal"> Let’s step back for a second and make an observation of this structure. Why would this structure exist? It exists because we want to make some sort of connection between name and nicknames. Doesn’t that sound an awful lot like what we should use a class for? Let’s write a class that provides the same connection:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Person</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> Name { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> Nicknames { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We then would also change our property to:</div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><div class="code"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Person</span>> People { <span style="color: blue;">get</span>; }<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">There is one thing that we are missing in this implementation. That is we’ve lost the ability to quickly lookup the nicknames based upon the name. We will ignore this for right now and revisit it later on once we develop our structure further.</div><div class="MsoNormal">Our class has created as strong relationship between our name and nickname. The relationship is explicit and there is no reliance on meta-data to understand the relationship. Using the old structure if we wanted to also map name to another value, like birthday, we’d have to create another property like this:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"><summary></span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> Gets a map of a user's name (the key) to their birthday </span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> (the value) so we can look up their birthday quickly</span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt;"></summary></span><span style="font-family: Consolas; font-size: 9.5pt;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">DateTime</span>> NameToBirthdayMap { <span style="color: blue;">get</span>; }<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">In creating this property, we have to ensure that we provide the same detail in the meta-data and naming to keep straight what we are mapping. If we want to create the same relationship using our class we just add a new property for the birthday and we have created the same relationship. Our Person class now looks like this:</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt;">public</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">class</span> <span style="color: #2b91af;">Person</span><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">{<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: blue;">string</span> Name { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> Nicknames { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">public</span> <span style="color: #2b91af;">DateTime</span> Birthday { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="font-family: Consolas; font-size: 9.5pt;">}<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We now have strong links between the name, nicknames, and birthday. This is simple object-oriented encapsulation and nothing revolutionary. We also are using an example that leads us naturally to think of an object. A person is an object type that is naturally created when we want to represent people in a system. We know we want to encapsulate data into a person object early in design because we know that a person has many characteristics we want to put together. We are using a person only as a concrete example. The type of situation we are discussing here is one where originally, there is a single relationship and over time, similar relationships are added. If our original relationship is done with a map then our future relationships will most likely be added with a map as well. This is natural because programmers tend to follow the pattern of existing code. Unless someone takes a step back at some point you easily could wind up with 5, 10, 20 maps mapping name to some other values. The class containing these mappings feeds on itself because as the pattern becomes more pervasive there is less incentive to change. This probably won’t happen with person data which can clearly be thought of in object terms. It can easily happen with abstract concepts within a system that are hard to translate into a real world object because people probably aren’t thinking of the relationships between values as object defining relationships. </div><div class="MsoNormal">Let’s take a step back and circle back to my previous point about circumventing the object orientedness of the language. When you use collections to make connections between name and nicknames or name and birthday you are creating a weak relationship. The relationship only exists as far as that Dictionary or HashMap exists. You haven’t broken the typing system and syntactically you are still correct, but you aren’t following good object oriented design practices. When you create the class that encapsulates the data you create strong relationships that are self evident to someone reading and using your code. </div><div class="MsoNormal">Again, this is not the full problem, but another stepping-stone onto seeing the problem and the remedy for it. It still can be manageable to handle data with only the collections if there is a small number of relationships. It is also easy to refactor if we begin to recognize we should encapsulate these relationships together. Next time we’ll start to see when writing code in this manner quickly becomes a problem as we add more levels.</div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com1tag:blogger.com,1999:blog-7045271175809923314.post-23762611766092757482010-11-24T11:22:00.000-08:002010-11-25T07:09:42.460-08:00HashMap of a HashMap of a HashMap Problem -- Part 1 - Fundamentals<div class="MsoNormal">Years ago, when I was working on my first project as a fresh developer out of school my lead developer and one of the other developers got into a shouting match about the use of HashMaps. The lead developer’s argument was basically “be sure you are using the appropriate data structure.”<span style="mso-spacerun: yes;"> </span>The developer’s argument was “of course it is right, HashMaps are fast, and I want fast access.”<span style="mso-spacerun: yes;"> </span>At the time, I thought the lead developer was making a mountain out of a molehill.<span style="mso-spacerun: yes;"> </span>It seemed obvious that the HashMap was appropriate in this situation.<span style="mso-spacerun: yes;"> </span>There was a reason for his reaction, which I only learned later when I became lead developer of the same project.<span style="mso-spacerun: yes;"> </span>During the course of the argument, he said something to the effect “I’ve seen HashMaps abused before, I just want you to be sure you are using them because you should, not because they are convenient.”<span style="mso-spacerun: yes;"> </span>If he would have given context to his argument he would have helped his position greatly.<span style="mso-spacerun: yes;"> </span>After some experience I’ve come to share his opinion.<span style="mso-spacerun: yes;"> </span>However,<span style="mso-spacerun: yes;"> </span>it was only after I saw the code he was referring to when he said he’s seen them abused.<span style="mso-spacerun: yes;"> </span>When I saw this code, I immediately understood his angst and it is something that has shaped the way I develop today.<span style="mso-spacerun: yes;"> </span>I am a better developer today because I understand the problem and avoid it.<span style="mso-spacerun: yes;"> </span>What is this problem?<span style="mso-spacerun: yes;"> </span>It is what I call the HashMap of a HashMap of a HashMap problem.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">I use the HashMap class to express this problem because I first encountered working on a Java project.<span style="mso-spacerun: yes;"> </span>It applies equally to any language and any collection types Dictionary, List, SortedSet, etc. <span style="mso-spacerun: yes;"> </span>I will use HashMap and Dictionary interchangeably within this series because they are essentially the same data structure. The crux of the problem is that collections can be used as a way to circumvent the object orientedness of languages like C# or Java.<span style="mso-spacerun: yes;"> </span>I say circumvent because they do not break the typing system, but they can be used to create pseudo classes that someone has to know meta-data about in order to use.<span style="mso-spacerun: yes;"> </span></div><div class="MsoNormal">In this first part I’m going to talk about the nature of using collections and how even the simple use of collections requires us to be careful.<span style="mso-spacerun: yes;"> </span>It is not an argument against using collections but the groundwork that will help illuminate the issue we are dealing with.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Let me start by saying I hate seeing a return type of a Dictionary<TKey,TElement>, especially if it propagated up through many methods.<span style="mso-spacerun: yes;"> </span>It’s not that this is bad code it is because of my experience has shown me that the information provided with the method is often not as robust as I’d like. I hate seeing <span style="mso-spacerun: yes;"> </span>it because it often means I have to trace the method calls down to the source to understand what values are in the collection.<span style="mso-spacerun: yes;"> </span>Let’s examine what I mean at a very basic level.<span style="mso-spacerun: yes;"> </span>Let’s say I have a property in C# defined like this:</div><div class="MsoNormal"><br />
</div><div class="code"><br />
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;">public</span><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">string</span>> NameMap { <span style="color: blue;">get</span>; }<o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"></div></div><br />
<div class="MsoNormal">Can you tell me what that property contains?<span style="mso-spacerun: yes;"> </span>Of course you cannot.<span style="mso-spacerun: yes;"> </span>You can make some guesses that one of the strings is a name of some sort and another might be a name or it might be something else completely.<span style="mso-spacerun: yes;"> </span>What the person in the code has done is created an implicit pair type and put it into a collection for quick access. <span style="mso-spacerun: yes;"> </span>With a Dictionary<string, string> data structure you are reliant on the meta-data to understand what it contains.<span style="mso-spacerun: yes;"> </span>Hopefully, the writer commented what the key and value were well, otherwise you’re going to have to use some archaeology to understand what the collection contains.<span style="mso-spacerun: yes;"> </span>This structure <span style="mso-spacerun: yes;"> </span>is not bad as long as we write the appropriate documentation and use good names for our properties and methods.<span style="mso-spacerun: yes;"> </span>In this situation good commenting and a little rename can go a long way.<span style="mso-spacerun: yes;"> </span>If I change the NameMap to be NameToNicknameMap its purpose becomes much clearer and I can guess the key is the name and the value is a nickname.<span style="mso-spacerun: yes;"> </span>Adding comments can make this clear still.<span style="mso-spacerun: yes;"> </span>Let’s change the comment as well and we get the following code:</div><div class="MsoNormal"><br />
</div><div class="code"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><summary></span><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"> Gets a map of a person's name (the key) to their nickname </span><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"> (the value) so we can look up their nickname quickly</span><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: grey; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;">///</span><span style="color: green; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"> </span><span style="color: grey; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"></summary></span><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"><o:p></o:p></span></div><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;"><span style="color: blue; font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;">public</span><span style="font-family: Consolas; font-size: 9.5pt; mso-bidi-font-family: Consolas;"> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">string</span>> NameToNicknameMap { <span style="color: blue;">get</span>; }<o:p></o:p></span></div></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We now can clearly understand that we are mapping from a name string to a nickname string. Therefore, our first lesson from this is good naming and good commenting can solve simple collection implicit typing problems.<span style="mso-spacerun: yes;"> </span>In the real world, I often find that even this level of detail is lacking.<span style="mso-spacerun: yes;"> </span>Developers often have an attitude that it is obvious what a collection contains, even though we’ll forget ourselves by the time we return to the code at some future point.<span style="mso-spacerun: yes;"> </span>It is important even in this simple case that we make it clear what the values we are handling are.<span style="mso-spacerun: yes;"> </span>Naming and comments go a long time to improve the maintainability of the code.<span style="mso-spacerun: yes;"> </span></div><div class="MsoNormal"><span style="mso-spacerun: yes;"><br />
</span></div><div class="MsoNormal">The important take away from this part of our series is that even simple collections require clarifying documentation.<span style="mso-spacerun: yes;"> </span>Without clarifying documentation they can be confusing, cause developers to guess at their meaning, or dig through other code to understand them.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">In the next part we will talk about adding complexity to the information we want available in our data structure and the implications on clarity that occur when we add complexity.</div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com0tag:blogger.com,1999:blog-7045271175809923314.post-30758173475961564972010-11-16T18:33:00.000-08:002010-11-16T18:34:44.533-08:00WPF Themes - Ensuring Hot Keys Display properly<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">In going through the themes in the <a href="http://wpfthemes.codeplex.com/">WPF Themes</a> project on CodePlex I've encountered many inconsistencies. Sometimes these inconsistencies are annoying and other times they require much more complicated fixes. All these issues are instructive because they teach us things to be aware of when building our own themes or even our own templates. </span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">I've written about some of the more complex issues I've encountered in the past. Today I'm just going to talk about one of the more simple problems. Some themes in the WPF Themes do not properly display the access keys. The underscore used to indicate the key was being displayed instead of removed. This is a simple problem to fix. </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ContentPresenters </span><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">have a property </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">RecognizesAccessKey</span><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">. If this property is not set, it defaults to false and the access keys will not work. Writing </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">RecognizesAccessKey="True"</span><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"> will make the access keys work properly.</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">I would have preferred the default for this property to true. In the general case I want the access keys to be active. An even better solution would be if there was a global way to specify the default for it. Using access keys is usually what you want to be application wide and it'd eliminate little presentation bugs to if this was possible. Its easy to forget to set this property on a ContentPresenter which can manifest in hard to find locations. Its an easy problem to fix, but annoying when you discover it.</span>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com0tag:blogger.com,1999:blog-7045271175809923314.post-35382977548721755342010-11-09T15:30:00.000-08:002010-11-09T18:26:31.975-08:00Neat Way to Write a Read-Only Extendable List<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">The other day one of my coworkers wanted to to do the following:</span><br />
<br />
<ul><li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">Have a base class that has a property that returns a list</span></li>
<li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">The list should be immutable</span></li>
<li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">The list will contain a list of items to exclude elsewhere in the code</span></li>
<li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">Sub-classes should be able to add items to the list but not remove them</span></li>
</ul><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">One way to implement this would be something like the following:</span><br />
<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class Base</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">{</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> private IList<string> _excludeList = (new List<string>(){ "a", "b", "c" }).AsReadOnly();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public virtual IList<string> ExcludeList</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> get { return _excludeList; }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class Subclass : Base</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">{</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public override IList<string> ExcludeList</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> get</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> List<string> excludeList = new List<string>(base.ExcludeList);</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> excludeList.Add("d");</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> return excludeList.AsReadOnly();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">My inclination was that this might be inefficient because of the repeated creation of the list. Let's examine a couple pieces of this code and see if we can clean it up. The first is we use a list because the framing of the question lead us there. We just want to be able to iterate over the list, how we accomplish that is unimportant, therefore List is not the type we want. There really is no reason that this needs to be something other than an IEnumerable.</span><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"> If we return an IEnumerable rather than a list we can use the yield keyword to do some fancy rewriting. We also are no longer creating new collections every time we call the subclass version:</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span><br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class Base</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">{</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> private IList<string> _excludeList = (new List<string>() { "a", "b", "c" }).AsReadOnly();</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public virtual IEnumerable<string> ExcludeList</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> get { return _excludeList; }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class Subclass : Base</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">{</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> public override IEnumerable<string> ExcludeList</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> get</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> foreach (string s in base.ExcludeList)</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> yield return s;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> yield return "d";</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">We now are avoiding creation of new lists and the way it works is fairly clean. The unfortunate part of this is that its not very efficient in the large case. In talking about this I originally thought this would be a more efficient way of doing meeting our requirements because there would be fewer lists being created. My quick performance testing showed quite the opposite. In the small cases the difference in performance is negligible; I could not get a consistent result of one being quicker than the other. In the case where I make the initial list "a" - "z" and the added items "aa" - "mm" the performance difference was significant. The rewritten version took about twice as long on average. I did not test a small initial list and a long additional list nor did I test a long initial list and a short additional list. The test case I ran proved to me that my theory about it being more efficient was wrong so I saw no reason to continue.</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">Since the performance of this method turns out to be poor this remains nothing more than an interesting way to use the yield operator.</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com0tag:blogger.com,1999:blog-7045271175809923314.post-48661247473022589032010-11-05T17:50:00.000-07:002010-11-05T17:50:49.491-07:00The Art of Commenting Code<div><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">When I first started programming I was horrible with comments. I honestly didn't write them because I didn't see the point. The reason I did not do it was because I was never forced to maintain any of my code. In school we often wrote little programs that were a couple hundred lines long that was discarded after each assignment. Despite my teacher's best efforts it never struck me as to why comments are necessary. I would comment my code when forced to by my teacher. This lead to inane commenting like the following:</span></span></span></div><div><span class="Apple-style-span" style="font-family: Arial; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><br />
</span></span></div><div><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">//Assign 5 to foo</span></span></span></div><div><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">int foo = 5;</span></span></span></div><div><span class="Apple-style-span" style="font-family: Arial; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><br />
</span></span></div><div><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">If anything my commenting here has hurt the readability of the code because it clutters it with needless information. If you know the language, you know what an assignment statement looks like, making the comment unnecessary. It was only once I started working on an J2EE application with approximately 200,000 lines of code that I understood why you comment. After much thinking about it I've come to the conclusion that you comment to justify the code. What I mean is if someone reading your code was to ask "Why does this code exist?" the comment should provide the answer. My comments tend to be long winded compared to most other developers I've encountered, because of this approach. I often make statements about the origin or the history of a piece of code to give context. I also believe in making the comment conversational or tell a story. This makes it both easier to read, more fun to read, and simplifies the communication. I'll write something like the following:</span></span></span></div><div><span class="Apple-style-span" style="font-family: Arial; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><br />
</span></span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">//The item has to be added to the collection before the call to the next function</span></span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">//because the control throws an exception if the item is not in the collection</span></span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">//yet. It'd be better if we could do it later on but we are limited by the existing</span></span></div><div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">//structure. If we refactor the control to use WPF we should revisit this.</span></span></div><div><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span></span></span></div><div><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">This of course is completely contrived and doesn't relate to any real code. I am trying to demonstrate what I believe is a good commenting style. I am doing the following things:</span></span></span></div><div><ul><li><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">I justify the positioning of the code and why it exists there. </span></span></li>
<ul><li><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">This lets a future developer (or which might be me) know why the code is set-up as it is and that the order has a logic to it and what that is</span></span></li>
<li><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">It also prevents a developer who is refactoring the code from unwittingly creating an error. I hate when I move something that appears to have no effect on the logic but then a strange edge case appears that causes an error. Even worse is when you talk to the original developer and they knew about the error potential but did not document it</span></span></li>
</ul><li><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">I also acknowledge any short comings. </span></span></li>
<ul><li><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">This is partly me protecting myself from future developers being to angry at me. I cannot count the number of times I've read someone's code and just questioned their sanity for coding something in a certain manner. There might have been logical justification for doing it that way and if I understood that I probably would accept it. I still may dislike the code but at least I now have context</span></span></li>
<li><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">This also provides information to someone who want to improve the code in the future. At some point in the future someone will be changing that code. There may be a way to perform the operation in a better manner. If that person may be less experienced with the code base or less experienced in general they may just assume that this is a good piece of code.</span></span></li>
<li><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">It raises a do not copy and paste this flag for people. Nothing is worse than seeing a poor piece of code copy and pasted. Inexperienced developers make this mistake often. They know a piece of code works but they don't understand it. They therefore copy, paste it, and never examine it closely. A comment that acknowledges short comings encourages a deeper level of thinking.</span></span></span></li>
</ul><li><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">Provide an upgrade path</span></span></span></li>
<ul><li><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">If there is some point in the future that the code be changed to remove the short comings and I know what that point is I mention it. I don't necessarily think that those short comings will be removed right away when that upgrade point change occurs but it provides a reference point to make the change.</span></span></span></li>
</ul></ul><span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;">Its also important to remember that comments are how future developers will be able to understand what the code does and why it does it. Reading comments is one way you can perform archeology on code to understand it. You therefore should leave behind artifacts for the future archeologists. </span></span></span><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: 13px;">Code doesn't exist in a vacuum. We use many other tools like requirements and defect tracking systems to help us manage development. We stage implementation in to releases. We have meetings to discuss functionality. We write using architectures and designs. All of these are important to the code, but rarely are they referenced in a meaningful way. Providing well placed linage to the outside materials can provide a wealth of information with the minimal actual writing.</span><br />
<span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><br />
</span></span></span><br />
<span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;">It is impossible to link every piece of code to meaningful external references, but sometimes providing that link is vital. The easiest link to provide is to requirements management systems and defect tracking systems that give unique identifiers that can be easily referenced. If a change for a requirement or a defect is fairly esoteric and isolated to a small code section I will often include the ID of the requirement or the ID in the comments for the code. Sure, a tool like subversion can be used to gain the same information, but that requires an additional step that most people will not undertake. It also gives me traceability back to the defect tracking system, which occasionally comes in handy on its own. Defects and requirements are not the only links that can be put in comments. If you keep meeting minutes or a record of conversations you can provide a link by putting in the date of the conversation that was the basis for the change. Architecture and design documents can be referenced in similar manners. Instead of trying to reexplain in detail why something works the way it does, reference the existing documentation. If a change significantly changes behavior starting at a certain version number, it doesn't hurt to mention that with that version number the functionality has changed.</span></span></span><br />
<span class="Apple-style-span"><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><br />
</span></span></span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;">You can go overboard with this to the point that it becomes annoying. Just like the first example of commenting an assignment statement, you don't want to make it so the comments lose meaning. For example I don't link to a defect number if the defect occurs because of a null reference that is avoided by a simple null check. Generally, I add the link and level of detail if</span></span><br />
<br />
<ul><li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: 13px;"> The change required significant archeology on my part</span></li>
<li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: 13px;"> If a fix for a defect was non-intuitive</span></li>
<li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: 13px;"> It seems likely that similar changes will need to be made in the future</span></li>
<li><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;">The way something was functioned was specifically prescribed by a meeting or a document</span></span></li>
</ul><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;">These are not hard and fast rules to follow, but more guidelines. I do not use the previous list as a checklist. In fact I had to reverse engineer when I actually do add links to outside information. It all comes down to a feel for the code and when its useful. You do not want the linkage to become pedantic, but want to provide others and yourself tools for the future. After all, you are as likely to be helping yourself as you are to helping others. Numerous times I have had to return to a piece of code I wrote and had to perform archeology on it because I couldn't remember writing it. We always feel we will remember the code we write. For the most part that just can't be true because of the sheer volume of code we write. It will save you time an energy in the long run to write good comments. Nobody really debates the merits of comments, so I won't continue down that line of thought. I do think the quality of comments is extremely important. I hope I've given you some thoughts on how to write good comments.</span></span><br />
<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><br />
</span></span></div><div><span class="Apple-style-span" style="font-family: Arial; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><br />
</span></span></div><div><span class="Apple-style-span" style="font-family: Arial; font-size: small;"><span class="Apple-style-span" style="font-size: 13px;"><br />
</span></span></div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com1tag:blogger.com,1999:blog-7045271175809923314.post-14182818314468508772010-11-01T18:26:00.000-07:002010-11-01T18:27:47.801-07:00WPF Gird Causing Memory Leak<div><div class="MsoNormal" style="margin-bottom: 0pt; margin-left: 0in; margin-right: 0in; margin-top: 0in; vertical-align: top;"><span class="Apple-style-span" style="font-family: Verdana, sans-serif; font-size: 8.5pt;">There is a fundamental problem in WPF that can cause a memory leak in applications using it. The problem is that a ColumnCollection in a Grid can become pinned in memory. It is not in all cases but in a specific case in the application I work on. I am not 100% about what in the structure caused it but there are 3 separate potential contributing culprits that I've identified. Without </span><span class="Apple-style-span" style="font-family: Verdana, sans-serif; font-size: 11px;">extensive</span><span class="Apple-style-span" style="font-family: Verdana, sans-serif; font-size: small;"><span class="Apple-style-span" style="font-size: 8.5pt;"> testing of the different </span><span class="Apple-style-span" style="font-size: 11px;">scenarios I won't be able to identify exactly what the cause was.</span><span class="Apple-style-span" style="font-size: 8.5pt;"> The three potential contributing culprits are:</span></span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; vertical-align: top;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in; tab-stops: list .5in; text-indent: -0.25in; vertical-align: top;"><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">1.<span style="font: normal normal normal 7pt/normal 'Times New Roman';"> </span></span><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">User control inside a DataTemplate with a Grid. It does not matter how deep in the control the grid was in the control all Grids were getting caught</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in; tab-stops: list .5in; text-indent: -0.25in; vertical-align: top;"><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">2.<span style="font: normal normal normal 7pt/normal 'Times New Roman';"> </span></span><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">Binding column widths from a parent grid to an inner grid through a border control. This was done to emulate a grid like behavior but allow for multiple control types within the grid</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in; tab-stops: list .5in; text-indent: -0.25in; vertical-align: top;"><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">3.<span style="font: normal normal normal 7pt/normal 'Times New Roman';"> </span></span><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">Binding and unbinding the collection view source every time the source of the observable collection changed. </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt; vertical-align: top;"><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">In trying to fix this problem it seemed as if it was related to the DataTemplate but it is unclear exactly what caused the issue. </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt; vertical-align: top;"><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">The actual leak came from the pinning of the Grid.ColumnCollection. The pinning of that caused all the associated control to be pinned as well. The Grid.RowCollection did not seem to have the same issue. This was still an issue even if there were no columns defined. It also occurred if a Grid was used inside a control from the same assembly. If the Grid was anywhere inside a user defined control in the same assembly, at any level, the issue would occur, even if it was in another user control. Crossing the assembly boundary appears to make this not occur. </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt; vertical-align: top;"><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt;">To fix the issue I replaced the Grids in the affected controls. The grids were replaced with a combination of StackPanels and DockPanels which can be used to replicate the grid. In this case they were actually more appropriate than using a Grid anyway. </span></div><span style="color: black; font-family: Verdana, sans-serif; font-size: 8.5pt; line-height: 115%;">The lesson from this appears to be that the use of a Grid over other LayoutPanel types should be carefully considered. If memory leaks start to appear with the Grid it needs to be changed to another Layout type.</span></div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com3tag:blogger.com,1999:blog-7045271175809923314.post-5795329472177789592010-03-05T10:31:00.000-08:002010-03-05T11:10:53.885-08:00.Net Framework Bug With SortingI came across a bug in the .Net Framework the other day.<br />
<br />
When specifying SortDescriptions on a CollectionViewSource there is a problem when using a complex path for the property name. This occurs when part of the path being checked is null. If I have the classes defined below<br />
<br />
class Foo{<br />
string Name {get; set;}<br />
<br />
}<br />
<br />
class Bar{<br />
Foo FooMember {get; set;}<br />
}<br />
<br />
If there is a CollectionViewSource that contains a list of Bar's and it is desired to sort each bar by Foo's name a SortDescription can be created as <br />
<br />
SortDescription d = new SortDescription("FooMember.Name", ListSortDirection.Ascending);<br />
<br />
If that SortDescription is added to the sort descriptions of the CollectionViewSoure it will properly order the items with one exception. This one exception is if there is an instance of Bar in the collection that the CollectionViewSource uses as the source. In this case an ArgumentException stating that there is a type mismatch and the element must be a string occurs. <br />
<br />
The reason this occurs is that in the Compare method of the SoftFieldComparer obtains a strange object when its accessing the instance of Bar that has a null FooMember. Rather than just being null, its an MS.Internal.NamedObject with a _name value of "DependencyProperty.UnsetValue". This is a problem because it then tries to do a comparison betwen the string and the NamedObject which cannot be compared, which causes the ArgumentException. This case needs to be handled to be able to sort items with null members.<br />
<br />
I have submitted this as an issue to Microsoft https://connect.microsoft.com/VisualStudio/feedback/details/539559/sortfieldcomparer-compare-method-can-throw-an-exceptionAnonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com2tag:blogger.com,1999:blog-7045271175809923314.post-46791522080585583412010-03-03T19:16:00.000-08:002010-11-16T19:00:18.700-08:00ContentPresenter, GridViewRowPresenter, and ListViewItemsThere are two distinct ways that content can be presented within control templates. These are the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridViewRowPresenter </span>and the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ContentPresenter</span>. The only place that the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridViewRowPresenter </span>is used is within a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView</span> to present the cell of data. This is needed for the binding path to be evaluated properly. If for example I have the class <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Foo </span>defined below:<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">public class Foo{</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> public string X {get; set;}</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> public string Y {get; set;}</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">}</span></span><br />
<br />
If I want to use a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ListView </span>presented using a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView </span>inside it to present the values of both <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">X</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Y</span> as columns you would write the following assuming the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">FooCollectionView </span>is a collection view source or some other collection of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Foo</span>'s<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"><ListView ItemsSource={Binding FooCollectionView}"></span><br />
<span class="Apple-style-span" style="font-size: small;"> <ListView.View></span><br />
<span class="Apple-style-span" style="font-size: small;"> <GridView ></span><br />
<span class="Apple-style-span" style="font-size: small;"> <GridViewColumn Header="X" DisplayMemberBinding="{Binding Path=X}" /></span><br />
<span class="Apple-style-span" style="font-size: small;"> <GridViewColumn Header="Y" DisplayMemberBinding="{Binding Path=Age}" /></span><br />
<span class="Apple-style-span" style="font-size: small;"> </GridView></span><br />
<span class="Apple-style-span" style="font-size: small;"> </ListView.View></span><br />
<span class="Apple-style-span" style="font-size: small;"></ListView></span></span><br />
<br />
If you want to define a style or control template that applies to this control instead of the normal location, where you'd put a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ContentPresenter </span>in the template you put a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridViewRowPresenter</span>. What happens if you use a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ContentPresenter </span>instead? You get the content presented but its not in a grid and its just the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ToString()</span> of the object. This obviously is not what you want to occur.<br />
<br />
Therefore, it seems fairly obvious that you should use a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridViewRowPresenter</span>. It however, is not that straightforward because what if you want to not use a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView </span>and instead just want to list them (the same as would be in a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ListBox</span>) so you have something like the following?<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"><ListView ItemsSource={Binding FooCollectionView}"></span></span><br />
<br />
What happens when you define the style with <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridViewRowPresenter </span>to present the content? The <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ListView </span>will appear to have no content because there is no <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView </span>to present the content of. This does not present a huge problem if you are defining a style on a per <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ListView </span>instance. However, it is a problem if you want to define a general style like you would in a theme. This presents a big problem because either you cannot use a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView </span>or must always use a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView</span>. You can get around this by using a ListBox anywhere you don't want to use a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView</span>. This strategy would mean letting the style dictate the form of the application which shouldn't be the case.<br />
<br />
However, the real problem occurs when defining a reusable theme. If you want to define a general purpose theme that others can reuse without having to alter thier application such as in the WPFThems project then you need it be able to handle both cases. On a side-note some of the themes in WPFThemes use the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ContentPresenter </span>and some use the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridRowViewPresenter</span>. This can make it so that the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ListBox </span>is shown properly with some themes applied and improperly with others.<br />
<br />
The fix to this is a bit of a hack but ultimatley turns out to work. It basically involves defining both presenters inside the control template. So where you put the presenters you put code that looks like the following:<br />
<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> <GridViewRowPresenter x:Name="gridrowPresenter"</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> Content="{TemplateBinding Property=ContentControl.Content}"/></span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> <ContentPresenter x:Name="contentPresenter"</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> Content="{TemplateBinding Property=ContentControl.Content}" Visibility="Collapsed"/></span></span><br />
<br />
<br />
To get the content to correctly display doing this. For the template the following trigger will need to be added:<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> <Trigger Property="GridView.ColumnCollection" Value="{x:Null}"></span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> <Setter TargetName="contentPresenter" Property="Visibility" Value="Visible"/></span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> </Trigger> </span></span> <br />
<br />
This trigger will show the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ContentPresenter </span>when the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridViewRowPresenter</span> has no content. Since there is no <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridView </span>the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">GridViewRowPresenter </span>will not display anything visually.<br />
<br />
Obviously, this is a bit of a hack to get around a flaw with how WPF works. Hopefully, in a future version this will be addressed in how the framework works.<br />
<br />
<div><span class="Apple-style-span" style="color: blue;">Edit 11/16/10 Added Visibility="Collapsed" property to the contentPresenter element which was a bug in the implementation</span></div>Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com11tag:blogger.com,1999:blog-7045271175809923314.post-36032606907793305852010-02-10T16:53:00.000-08:002010-02-10T16:54:45.027-08:00SourceName In MultiTriggers in WPF ThemesThere is a bug in the WPF code that can cause a null pointer exception. The null pointer exception occurs on line 5924 of System.Windows.StyleHelper.cs :<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">object evaluationValue = evaluationNode.GetValue( conditions[i].Property );</span></span><br />
<br />
The problem has to do when you are defining a MultiTrigger on an element in a theme. This bug manifested itself when on our project we were refreshing a collection that was bound to a TreeViewer and the TreeViewItem style had a MultiTrigger in it. The style in question comes from the <a href="http://www.codeplex.com/wpfthemes">WPFThemes project</a> and was the ExpressionDark Theme (the problem occurs in about 7 of the other themes in the project). The one Condition on the MultiTrigger in the theme has a SourceName defined for it. The SourceName was not needed because it was the element right inside the root element anyway. This bug was especially subtle because it would only manifest itself after other conditions would have happened that would cause the MultiTrigger to fire.<br />
<br />
I suspect, but have not verified, that the precondition for causing this bug is having a currently selected TreeViewItem that is removed upon refreshing the control and a newly generated item in the refresh was being set as the selected item in its stead. The trigger was checking the condition but the new item hadn't fully been generated so when it was looking for the child element it didn't yet exist. This makes sense in context of the code in the StyleHelper class. The code that returns the element using the GetChild method defined on line 6388. The comment inside the method says:<br />
<br />
<code><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> // Notice that if we are requesting a childIndex that hasn't been</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> // instantiated yet we return null. This could happen when we are </span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> // invalidating the dependents for a property on a TemplateNode and</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> // the dependent properties are meant to be on template nodes that</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> // haven't been instantiated yet.</span></span><br />
</code><br />
<br />
This method was returning null because<br />
<br />
<br />
<code><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">if (styledChildren == null || childIndex > styledChildren.Count)</span></span></code><br />
was evaluating to true because <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">styledChilderen </span>was null. <br />
<br />
The null pointer exception was occurring because line 5924<br />
<br />
<code><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">object evaluationValue = evaluationNode.GetValue( conditions[i].Property );</span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
</code><br />
was assuming evaluationNode as not null. <br />
<br />
It was assuming it could do this because of the Debug.Assert on line 5903:<br />
<br />
<code><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">Debug.Assert(evaluationNode != null, </span></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;"> "Couldn't find the node corresponding to the ID and name given in the trigger. This should have been caught somewhere upstream, like StyleHelper.SealTemplate()." );</span></span><br />
</code><br />
<br />
This brings up a point about using Debug.Asserts in code. People often use them (I see it on my project often) when they don't want to perform the null check overhead or other conditions that they feel should never happen. The idea is that you should catch any of these cases in testing. Obviously this is a case that was over looked in Microsoft's testing. The method that set the value of evaluationNode before the Assert has a perfectly legitimate reason for returning null (see the comments earlier) then its not reasonable to use the Assert here. More on a future post about using Asserts versus null checks.<br />
<br />
The work around for this bug was to remove the SourceName from the MultiTrigger. This does not change the style in a meaningful way and removes the null pointer exceptionAnonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com7tag:blogger.com,1999:blog-7045271175809923314.post-36181824295960625062009-10-20T18:48:00.000-07:002009-10-20T18:48:57.276-07:00Problems with Parameters and the Command Object in ODBC and OLE DBIn testing a web service that retrieves a set of records a member of my project team came across an odd behavior. The function that selected a list of records was slowing down when selecting a high volume of records 800-2000. At the time we were using the ODBC Command object and placing parameters in to narrow the selection of records to the set that was to be returned. By instrumenting the code with timestamps he was able to determine that the unexpected slowdown was in the retrieval of records. The odd part about the slow down was that it was occurring somewhere around 300 records in when he was selecting 800 records. Somewhere around the 300th record there would just be about a 90 second pause in the retrieval. This was an odd boundary. My first inclination was that there was something bad with a specific record that caused this. However, on running multiple iterations it was not always the same record that was causing the slow down. What was being selected was also only two fields. One field was an int and the other was a string no larger than 128 characters. <br />
<br />
Having this information made the problem even stranger. I suggested that he change the ODBC objects over to be the newer OLE DB objects figuring it might be a bug with the ODBC Command or with something with how ODBC Command was retrieving records. The same behavior was demonstrated using OLE DB. This made the problem even more puzzling. My next thought was that there was some sort of locking taking place somewhere. This seemed unlikely given the simplicity of the database accesses and the lack of long running transactions. The repeatability also make this unlikely as well. Again, my team member came back to me with a negative report. <br />
<br />
At this point I had him test it with retrieving more records. The results of this were odd as well. When he tested it with 1500 records the problem would happen at about 1000. When he used 2000 records the pause happened at about 1500. He couldn't test it with many more than 2000 records because that is the maximum number of parameters that can be put on a command object. This was a very odd pattern to be exhibiting. Why approximately 500 records from the end of the result set was a pause occurring.<br />
<br />
It was at this time that the maximum of approximately 2000 records retrieved was realized because of the parameter limit. The reason that this issue was first discovered was that we were looking to be able to run the method in the Web Service to retrieve 5000 records efficiently. Obviously we could not have a 2000 record limit or we'd have to have multiple queries. We however were not really using parameters for their intended purposes really. One of the fatal flaws with all database connection objects I've seen in Java and in C# are that there is no way to easily push a list into an IN clause. Instead you wind up writing <c><span style="font-family: "Courier New",Courier,monospace;">value = 1 OR value = 2 etc.</span></c> What we were doing was just adding where the values were and modifying the query string and then adding a parameter for each '?'. This strikes me as bad to begin with. If you are already modifying the query string you are not getting any benefits from having the compiled version cached. Instead of entering the '?' we should have just been using a <span style="font-family: "Courier New",Courier,monospace;">StringBuilder </span>and creating the query on the fly. We really weren't using parameters the right way anyway. <br />
<br />
After some discussion we decided that making this change made sense in the code. It was implemented building the condition dynamically and tested again. Magically the 90 seconds of delay disappeared. That meant we killed two problems at once. Our delay that caused the Web Service to time out was gone and we were no longer capped at about 2000 records. What did this mean about our problem though. It appears that there is a bug with both ODBC and OLE that if you try to have more than 500 parameters or so, they will freeze for an undetermined amount of time, for no good reason. You must therefore heavily consider what you are doing if you have 500 or more parameters. Analyze your code and you probably will find that there is some other change that can be made to eliminate that many parameters and you should no longer have that problem.Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com0tag:blogger.com,1999:blog-7045271175809923314.post-59927095075912554442009-10-18T19:19:00.000-07:002009-10-18T19:19:32.336-07:00Windows Forms & WPF Element Host Bug And How to Fix ItIf you haven't had the chance to look at what Microsoft did with the advent of the Windows Presentation Framework (WPF), I suggest you check it out. As a revamp of how Windows Applications are written it is pretty spot on with what needed to be done. I could ramble about how much I like WPF for a while but that's not the point of this post. <br />
<br />
In an ideal world we would be able to rewrite our applications with new technologies, especially ones that improve our maintainability and improve its over all quality. However, in the real world this is not really feasible. We have budget, time, and customer constraints. Many times existing code has domain knowledge impeded in a non-extractable way. As much we as developers want to play with technologies and use the latest greatest things these constraints don't allow us to. Microsoft has recognized that we want to use new technologies in existing applications or we want to take an incremental approach to transition our applications. In order to help with either of these plans they have provided the ElementHost control which allows you to put WPF controls on a Windows Form. <br />
<br />
The ElementHost is great conceptually and great when it is working, however it has a fundamental bug. What is this bug you may ask? The bug is that by default the controls contained in the element host will always be disabled because the enable property won't propagate through to them. This basically makes them read only controls. The good news is that there is a work around for it, however it is non-intuitive because it uses Win32 Interop. I was only able to know what to do once I found Microsoft's page about the bug. There are not really any references to it unless you search very specifically. The solution to the problem can be found here: <a href="http://support.microsoft.com/kb/955753">http://support.microsoft.com/kb/955753 </a><br />
<br />
I recommend you create a class that derive a class from ElementHost and having that as part of your repository and use that for incorperating WPF controls into windows forms.<br />
<br />
A couple side notes. This is only necessary if you have a Windows Form that you want to place WPF controls on. You can open a WPF Window in a Windows Form application as if was just another form so this is not necessary if you just want to combine WPF and Windows Forms inside the same application. Anonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com1tag:blogger.com,1999:blog-7045271175809923314.post-26626656635865071842009-10-18T11:53:00.000-07:002009-10-18T11:53:25.702-07:00Initial PostingI've always thought blogs were kind of a dumb idea where people talk about the minutia of life. I've recently come around on the concept of blogs being useful for technical purposes. I am finding that more and more in my professional life that blogs are good places for people to help others with posting information. There will be none of the unnecessary posting of crap that nobody will care about on this blog. Instead I will be posting things I find to be relevant and useful to other people. This means that this will be mainly focused on technical topics that I find useful.<br />
<br />
I am a software developer. That means technical topics that are interesting to me will be what winds up on this blog. I spent the first few years of my career working in a Java environment but have been spending my recent time working in .Net. I have an appreciation for both platforms and think both have their uses and appropriate usages. I get excited about new ideas and new ways that improve how we program. I did start programming in C/C++ and don't know if I can ever go back to the unmanaged programming. Java and C# both have transformed the way I think of code and what I expect out of a compiler. I have also started to work some in Python so I have a appreciation for that language as well. <br />
<br />
What I expect to wind-up on this blog is musings, technical tips, and just general technical topics I find interesting. I hope that what I write here is going to be a help to someone at some point. I have received so much help from others through blogs that I think this is really me giving back to others. I hope something here someday helps youAnonymoushttp://www.blogger.com/profile/05500709495640394356noreply@blogger.com2