<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7956719137458583385</id><updated>2011-11-27T16:05:22.214-08:00</updated><category term='NUnit'/><category term='xml'/><category term='rule object'/><category term='rules'/><category term='object discovery'/><category term='beer'/><category term='Continuous Integration'/><category term='About Face'/><category term='refactoring'/><category term='collaboration'/><category term='Web Services'/><category term='bills'/><category term='SharePoint'/><category term='Alan Cooper'/><category term='three-tiered architecture'/><category term='Groovy'/><category term='mvc'/><category term='C#'/><category term='CruiseControl.NET'/><category term='constraints'/><category term='grails'/><category term='inheritance'/><category term='WSDL'/><category term='contradiction'/><category term='Agile'/><category term='haskell'/><category term='object thinking'/><category term='object thinking semantic net'/><category term='unit testing'/><category term='random thoughts'/><category term='humble dialog'/><category term='description object'/><category term='crc cards'/><category term='design'/><category term='anthropomorphization'/><category term='database'/><title type='text'>Tim Stewart's Blog</title><subtitle type='html'>Thoughts on Software Development and more.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-283096389735146826</id><published>2010-07-06T21:44:00.000-07:00</published><updated>2010-07-06T21:49:12.904-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>When To Use Abstract Classes</title><content type='html'>&lt;div&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Up until recently, my C# designs never started off containing abstract classes.  Things always started their lives as either concrete classes or as interfaces.  Occasionally an abstract method would appear in a class but that was the exception.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had read that abstract classes weather change better than interfaces but that wasn't enough for me to embrace abstract classes.  The limitation that a class can only inherit from one class was enough to keep me from "wasting" my one and only one inheritance card on an abstract class.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But then I re-read "Framework Design Guidelines" by Cwalina and Abrams and I thought I'd give abstract classes a second chance.  They encourage their readers to use abstract classes.  I wanted to try out their advice, but I wanted to have a game plan so that I wouldn't completely give up on interfaces.  Here are the key points that guide me when choosing between interfaces and abstract classes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Interfaces Are Weak Contracts&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In their capacity as contracts, interfaces are really weak.  All an interface can do is enforce method signatures and property types.  Interface implementers can make their methods do whatever they want.  They can throw whatever exceptions they want to.  Interface implementers don't have to respect Barbara Liskov or her Substitution Principle.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Template Methods Provide Contracts With Teeth&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A template method is a design pattern where a method calls one or more virtual methods.  The template method might have knowledge about how the virtual methods should be called, under what condition they should be called, or what should be done before and after the calls to virtual methods, etc.  To some extent the template method design pattern can be used to give a contract some teeth.  For example, if a first virtual method does not meet a particular criteria, perhaps the second virtual method won't be called at all.  But if the first virtual method does meet the criteria, the second virtual method will be called.  What better way to express this template method than as an abstract class?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Core Abstractions Are Likely To Change&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If your application's core abstraction is a Map, it is very likely to change over time as you allow your users to do more and more with a Map.  It is also likely that different kinds of maps will be introduced which will result in an inheritance hierarchy.  When you add the "Print Map" feature, Map may acquire some print functionality which would change its interface.  Representing this core abstraction as an interface sets up your users for breaking changes.  Representing this core abstraction as an abstract class does not offer perfect isolation from change but it can make change a good deal easier.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Core Abstractions Should Collaborate&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I like anthropomorphic objects.  If I have a Map and I want to print it, I want to be able to tell the Map to print itself.  I don't want to have to instantiate a MapPrinter object and tell it to print the map.  However, I don't want my Map object to know about printing APIs.  To make Map anthropomorphic without depending on printing APIs, I'd introduce a collaborator that Map can interact with.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;C# Supports Single Inheritance Only&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As nice as abstract classes are, any given class can at most derive from one of them.  This tells me that abstract classes are precious resources.  My recently adopted philosophy is that if an abstraction represents essential qualities, it should be modeled as an abstract class.  For example in a drawing application, the Shape abstraction represents the essence qualities of squares, circles, and polygons.  On the other hand, if an abstraction represents capability or a role, it should be modeled as an interface.  For example, shapes might be serializable.  Serializability is not part of the shape's essence but it does express one of the Shape's capabilities: the ability to serialize itself.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These five key points guide me as I decide when I should model an abstraction as an interface or as an abstract class.  The last point about essential qualities vs. capability is the strongest guide.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;The Rub - Unit Testing&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is the rub with abstract classes that adhere to the template method pattern as I've described it.  It's very difficult (impossible?) to mock away abstract classes with non-virtual methods such that no production code for the abstract class winds up in your unit test.  Here is where the interface shines; mocking the interface is a snap!  So does this mean that I should give up on abstract classes?  I don't think so.  Abstract classes can be used in unit tests as long as the following criteria are met:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Abstract classes should have their &lt;b&gt;dependencies injected&lt;/b&gt;.  If your abstract class connects to a database in its constructor, no amount of mocking will isolate your unit test from the database.  The down side of this is that to mock away an abstract class, you may need to create a mock for the abstract class and any dependencies that the abstract class my require during the course of the test.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Abstract class logic should be &lt;b&gt;tested in isolation&lt;/b&gt; from the production classes that derive from it.  This can be achieved partly through deriving a number of test-only classes from the abstract class such that the virtual methods of the derived classes put the abstract class logic through its paces and achieve good code coverage.  Abstract class logic can also be tested in isolation by injecting different dependencies into the abstract class such that the abstract class' logic is put through its paces.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Concrete classes derived from the abstract class are also tested in isolation from the abstract class' dependencies.  By testing the abstract class and the derived classes independently, you achieve a higher level of certainty that your code will be correct.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-283096389735146826?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/283096389735146826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=283096389735146826' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/283096389735146826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/283096389735146826'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2010/07/when-to-use-abstract-classes.html' title='When To Use Abstract Classes'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-4268391764465705039</id><published>2010-04-17T11:31:00.000-07:00</published><updated>2010-04-17T12:06:19.870-07:00</updated><title type='text'>Rethinking the Evil of XML Configuration Files</title><content type='html'>Do you remember when your system's configuration grew from a simple file containing a few name/value pairs modified by a small set of people, into a large collection of files in multiple locations with their own business processes surrounding them?&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When the config files were small and informal, you could easily get by with a YAML file or a Windows .INI file format.  But now that there are hundreds or thousands of settings, maintaining them all has become challenging.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The main problems with YAML and .INI configuration files are:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Lack of Type Safety - If the configuration reading code expects 'true' or 'false' and the configuration file contains '1', how will the code handle that input?  Will it log an error?  Will it silently misinterpret the '1' as 'false'?  Do you want to have to write type-checking code throughout your application?  You could write a comment in the configuration file that specified the type of the setting but not everyone understands all the various types and formats (e.g. dates and times).&lt;/li&gt;&lt;li&gt;Lack of Range Checking - If the configuration code expects a value between 1 and 4 inclusive, and someone has configured the setting as 5, how will your system react?  What if your configuration reading code expects 'high' or 'low' and someone enters 'medium'?  That's another form of range violation.  You could write comments that specify the range but the comments had better agree with the code that does the actual range checking.&lt;/li&gt;&lt;li&gt;Lack of Validation Support - If one of your configuration settings is mandatory for the system to operate correctly (e.g. a web service endpoint) and it's missing, you don't discover the error until run-time.  You could add a comment to the configuration file that stated that the setting was mandatory, but will people read it?&lt;/li&gt;&lt;li&gt;Lack of Appropriate Defaults - If some of your configuration values have appropriate defaults that you want to communicate to the user, you are stuck writing comments in the YAML or .INI file that list the defaults.  Unfortunately, you have now just introduced duplication between the code that must take the default when the configuration value is missing and the comment in the configuration file. &lt;/li&gt;&lt;/ul&gt;&lt;div&gt;XML files and, more specifically, XSD files, provide for all of the above.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;XSD allows you to specify the type of a given configuration value.  If your configuration value has the wrong type, XSD validation of the configuration file will alert you to your mistake.&lt;/li&gt;&lt;li&gt;XSD has support for range checking of several types.&lt;/li&gt;&lt;li&gt;XSD by it's very nature handles validation.  If your application does XSD validation upon startup, you can quickly catch configuration errors.&lt;/li&gt;&lt;li&gt;XSD allows you to specify default values for configuration settings.&lt;/li&gt;&lt;li&gt;With an XSLT transform you could generate an HTML document that would list all your settings along with their defaults.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;In short XSD codifies and enforces all of the constraints that we would otherwise add to our configuration files as comments.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Maybe XML configuration files aren't completely evil.  The main complaint I had about XML configuration files was that they were &lt;i&gt;so hard to get right&lt;/i&gt;.   Isn't that ironic!   YAML and .INI files are &lt;i&gt;hard to prove that they're right&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How many of my YAML and .INI files are wrong and I just don't know about it?&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-4268391764465705039?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/4268391764465705039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=4268391764465705039' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/4268391764465705039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/4268391764465705039'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2010/04/rethinking-evil-of-xml-configuration.html' title='Rethinking the Evil of XML Configuration Files'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-2076737874952100744</id><published>2010-03-27T20:14:00.001-07:00</published><updated>2010-03-27T20:37:46.994-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>NUnit and CruiseControl</title><content type='html'>&lt;div&gt;&lt;div&gt;One of my goals is to become more skilled with CruiseControl.NET because Continuous Integration plays a big part in Agile Development.  Today I took the first step.  It wasn't one of those easy, comfortable steps.  That's why I'm documenting my results.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here are some of the steps I took today to get a CruiseControl server running on my computer with integrated NUnit Reports.  Some of these steps could definitely be improved upon.  I don't like using absolute paths if I don't have to but I broke that rule left and right.  This is just the first time I've gotten all this working (and trust me, it took hours).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Install Cruise Control&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I installed version 1.5.6804.1 of CruiseControl.NET and after realizing that by default Vista does not enable ASP.NET, it ran quite nicely.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Incorporte NUnit into the Build Process&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wanted to make NUnit run as part of the Visual Studio 2008 build process.  I tried to use the &lt;a href="http://sdctasks.codeplex.com/"&gt;Microsft SDC NUnit Task&lt;/a&gt;  but after hours of tracking down unhandled exceptions in the NUnit task, I decided to switch to &lt;a href="http://msbuildtasks.tigris.org/"&gt;Tigris' MSBuild NUnit Task&lt;/a&gt; which worked great the first time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had to import the tasks in my Unit Test assembly's csproj file:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;   &amp;lt;Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And then I added the following to the same csproj file:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &amp;lt;IemGroup&amp;gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;TestAssemblies Include="$(TargetPath)"/&amp;gt;&lt;/div&gt;&lt;div&gt;  &amp;lt;/ItemGroup&amp;gt;  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &amp;lt;Target Name="Test"&amp;gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;NUnit &lt;/div&gt;&lt;div&gt;      Assemblies="@(TestAssemblies)"&lt;/div&gt;&lt;div&gt;      ToolPath="C:\Program Files (x86)\NUnit 2.5.3\bin\net-2.0" /&amp;gt;&lt;/div&gt;&lt;div&gt;  &amp;lt;/Target&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The last step was to add "Test" to the Project element's DefaultTargets attribute:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &amp;lt;Project ToolsVersion="3.5" DefaultTargets="Build;Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, whenever I built the project, the tests would run.  If the tests failed, the build would fail too.  I had to change the MSBuild verbosity to normal to see the actual results of the unit tests.  This has the side-effect of showing too much information.   If I figure out how to get the NUnit test results showing without showing too much information, I'll write another blog entry.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Build the Project with CruiseControl&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I added the following to my ccnet.config file:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &amp;lt;project name="MyProduct"&amp;gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;category&amp;gt;Production Code&amp;lt;/category&amp;gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;tasks&amp;gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;msbuild&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;executable&amp;gt;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe&amp;lt;/executable&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;workingDirectory&amp;gt;C:\Users\Tim\Projects\CruiseControl\CruiseControlTests&amp;lt;/workingDirectory&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;projectFile&amp;gt;CruiseControlTests.csproj&amp;lt;/projectFile&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;buildArgs&amp;gt;/noconsolelogger /p:Configuration=Debug /p:Platform=AnyCPU /v:diag&amp;lt;/buildArgs&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;targets&amp;gt;Build;Test&amp;lt;/targets&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;timeout&amp;gt;900&amp;lt;/timeout&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;logger&amp;gt;C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll&amp;lt;/logger&amp;gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;/msbuild&amp;gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;/tasks&amp;gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;publishers&amp;gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;merge&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;files&amp;gt;&lt;/div&gt;&lt;div&gt;          &amp;lt;file&amp;gt;C:\Users\Tim\Projects\CruiseControl\CruiseControlTests\TestResult.xml&amp;lt;/file&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;/files&amp;gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;/merge&amp;gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;xmllogger/&amp;gt; &lt;/div&gt;&lt;div&gt;   &amp;lt;/publishers&amp;gt;&lt;/div&gt;&lt;div&gt;  &amp;lt;/project&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The merge elements are required so that the output of the unit test run could be reported on.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Getting Reporting To Work&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the dashboard.config file I had to make a few changes too.  To make a change take effect, I'd recycle the CruiseControl app pool.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I added the following elements (shown in context):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    &amp;lt;buildPlugins&amp;gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;buildReportBuildPlugin&amp;gt;&lt;/div&gt;&lt;div&gt;        &amp;lt;xslFileNames&amp;gt;&lt;/div&gt;&lt;div&gt;          &amp;lt;xslFile&amp;gt;xsl\unittests.xsl&amp;lt;/xslFile&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and then I added this right after &amp;lt;/buildReportBuildPlugin&amp;gt;: &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;xslReportBuildPlugin description="NUnit Details" actionName="NUnitDetailsBuildReport" xslFileName="xsl\tests.xsl" /&amp;gt;&lt;/div&gt;&lt;div&gt;      &amp;lt;xslReportBuildPlugin description="NUnit Timings" actionName="NUnitTimingsBuildReport" xslFileName="xsl\timing.xsl" /&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After recycling the app pool, everything worked great.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-2076737874952100744?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/2076737874952100744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=2076737874952100744' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2076737874952100744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2076737874952100744'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2010/03/nunit-and-cruisecontrol.html' title='NUnit and CruiseControl'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-1403164934880439326</id><published>2010-01-13T20:53:00.000-08:00</published><updated>2010-01-13T21:11:34.213-08:00</updated><title type='text'>Can we drop the S in SOLID?  (Or NTP!)</title><content type='html'>&lt;div&gt;Maybe I just don't get the &lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;Single Responsibility Principle&lt;/a&gt; (SRP).  Maybe it's just named poorly.  I like the O, L, I, and D principles plenty, but my stomach feels anything but SOLID when I hear about the SRP.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;According to &lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;Wikipedia&lt;/a&gt;, "[Robert C.] Martin defines a responsibility as a reason to change".  I wish Martin had picked another, less useful word to redefine.  So now, to even think the acronym SRP, I have to pause mentally before the R, and then mentally replace it with RtC (as in Reason to Change).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even with this mental substitution, I still have problems with SRP.  Is the SRP telling me that every one of my classes should have one and only one reason to change?  How can this be, especially if a class has multiple responsibilities (as defined by Webster and &lt;a href="http://www.amazon.com/Object-Design-Roles-Responsibilities-Collaborations/dp/0201379430"&gt;Wirfs-Brock&lt;/a&gt;, not Martin)?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's my problem.  In the Business Layer I like classes that resemble their real-world counterparts.  For example, the Account object resembles a real account.  The SRP principle would tell me that if my Account object had more than one reason to change, I should split it up.  So if an Account object can calculate its balance, and perform a withdrawal, those are two places where the Account could change.  Both of those responsibilities (think Webster) could change for any number of reasons.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I refuse to break up a domain-specific class just for some arbitrary limit on the number of reasons to change.  We expect that change will happen.  That's one of the reasons why we refactor our code and write unit tests.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yay OLID.  Boo S.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By the way, NTP from the title stands for No Teal Principles (where I've redefined Teal to mean Useless and Overly Restrictive).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-1403164934880439326?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/1403164934880439326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=1403164934880439326' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/1403164934880439326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/1403164934880439326'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2010/01/can-we-drop-s-in-solid-or-ntp.html' title='Can we drop the S in SOLID?  (Or NTP!)'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-4833476079070452089</id><published>2009-12-24T12:12:00.000-08:00</published><updated>2009-12-24T12:40:40.710-08:00</updated><title type='text'>Helping Others for Fun and Profit</title><content type='html'>Perhaps, like me, you've found yourself saying:&lt;div&gt;&lt;ul&gt;&lt;li&gt;I want to write a program but I can't think of any real-world problem to solve*.&lt;/li&gt;&lt;li&gt;I want to be able to show a prospective employer some of my code but my previous employers own all of the code I've written and they would not let me show it to others.&lt;/li&gt;&lt;li&gt;I want to learn how to gather requirements and more effectively convert them into code but I can't talk with our customers.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I think I've stumbled upon a way of meeting these desires.&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Find a friend, relative, or charity who has a problem that can be solved by software.&lt;/li&gt;&lt;li&gt;Offer to write some software to solve their problem.  If they refuse, jump to step 1 with someone else.  I would recommend that you offer to do the work pro bono publico.&lt;/li&gt;&lt;li&gt;Sign any non-disclosure agreements that might apply but stress that you will own the code you produce.  After all, you want to be able to show the code to prospective employers.&lt;/li&gt;&lt;li&gt;Sit down with them and gather requirements.&lt;/li&gt;&lt;li&gt;Write the software as professionally as you know how in an iterative fashion seeking their input whenever it's needed (while respecting their time and schedules).   Keep in mind that one of the goals of writing the software is to maintain the friendship.  Buggy code may strain the friendship or even destroy it if the bug is serious enough.&lt;/li&gt;&lt;li&gt;Make sure that you protect yourself by releasing yourself from all liability just in case you have a litigious friend.&lt;/li&gt;&lt;li&gt;Deliver the software, the source code, and unit tests, and let them know that you'll be available to modify it if their needs change.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;If you find that your friend is taking advantage of you, you may have to set some boundaries to protect the friendship.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By the way, the profit I was referring to in the title of this article is not necessarily monetary profit, but it definitely is personal and professional profit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;NOTICE: I am not responsible for any friends you may lose, family members who disown you, or charitable organizations who publicly defame you or sue after you follow these steps.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Perhaps that's why there are so many ray tracers and sudoku solvers.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-4833476079070452089?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/4833476079070452089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=4833476079070452089' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/4833476079070452089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/4833476079070452089'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2009/12/helping-others-for-fun-and-profit.html' title='Helping Others for Fun and Profit'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-1691945223368447425</id><published>2009-12-24T11:53:00.000-08:00</published><updated>2009-12-24T12:11:02.279-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mvc'/><category scheme='http://www.blogger.com/atom/ns#' term='humble dialog'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><title type='text'>Resisting the Urge To Refactor</title><content type='html'>I'm working on the main Controller (as in the C in MVC) of a GUI application and trying to design the Controller along the lines of "&lt;a href="http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf"&gt;The Humble Dialog&lt;/a&gt;" [PDF] by Michael Feathers.  Some of the Controller's methods make repeated calls to the View object.  For example:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;view.clearAuctionEvents();&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;view.enableUpdateDatabaseButton(false);&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;view.displayErrorMessage("Could not download email messages.");&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My first instinct was to follow the Refactoring advice of Fowler and Beck and move these three calls into a new method on the View.  Then it struck me that it's actually desirable for the Controller to be so pedantic with the View.  After all, I'm trying to "humiliate" the view as "The Humble Dialog" article puts it by stripping it of any logic or behavior.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So sometimes it's okay not to refactor.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-1691945223368447425?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/1691945223368447425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=1691945223368447425' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/1691945223368447425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/1691945223368447425'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2009/12/resisting-urge-to-refactor.html' title='Resisting the Urge To Refactor'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-3890149940224824339</id><published>2009-12-05T13:55:00.000-08:00</published><updated>2009-12-05T14:36:30.589-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='WSDL'/><title type='text'>Rapid Web Service Construction with Groovy</title><content type='html'>I'm reading Thomas Erl's book, "Principles of Service Design" and, when he discusses contracts, they're usually codified in WSDL and XSD.  So I've been trying to find a way to quickly throw together Web Services that use WSDL and XSD so that I can play with some of the book's concepts.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Failed Attempts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I thought that Ruby would be the answer.  I first tried SOAP4R but found that it could not generate WSDL from service methods and types.  Since I don't want to generate WSDL files yet, this was a deal-breaker.&lt;br /&gt;&lt;br /&gt;I then tried Ruby's ActionWebService but the generator script was not installed correctly so it wouldn't work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Success&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I then stumbled upon &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;'s &lt;a href="http://groovy.codehaus.org/GroovyWS"&gt;WSServer&lt;/a&gt; library (&lt;a href="http://groovy.codehaus.org/GroovyWS+installation"&gt;installation instructions&lt;/a&gt;).    Groovy is a dynamic language that runs on the JVM.  I installed the &lt;a href="http://groovy.codehaus.org/Eclipse+Plugin#EclipsePlugin-GettingBuilds"&gt;Groovy support for Eclipse&lt;/a&gt; and had created a fully working web service in minutes.  I fired up the Web Service from within Eclipse and  then switched over to Microsoft Visual Studio and imported the Service Reference and called my service code from C#.  It was so easy.&lt;br /&gt;&lt;br /&gt;I then thought I'd try a web service call that would return a complex type (e.g. a Person object).  This made the Web Service crash with a stack overflow.&lt;br /&gt;&lt;br /&gt;It took me hours to find the solution.  The following links helped a lot:&lt;a href="http://groovy.codehaus.org/Using+the+Aegis+mapping"&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://groovy.codehaus.org/Publishing+a+web-service"&gt;Basic Service&lt;/a&gt; - This page showed how to create a simple Web Service.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groovy.codehaus.org/Using+the+Aegis+mapping"&gt;Using the Aegis Mapping&lt;/a&gt; - This showed me that I needed to create a mapping XML element for the Person class that ignored the 'metaClass' property of my Person object.  My guess is that the stack overflow was caused by navigating a very deep or even cyclic object graph during the serialization process.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://xfire.codehaus.org/Aegis+Binding"&gt;Aegis Binding&lt;/a&gt; - This link told me where to put the mapping XML element.&lt;br /&gt;&lt;br /&gt;Now I can create Web Services very quickly just to try things out.  And they run on any platform Groovy runs.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Have you found a better way to quickly develop Web Services?  I'd love to hear about what you've found!&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-3890149940224824339?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/3890149940224824339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=3890149940224824339' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3890149940224824339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3890149940224824339'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2009/12/rapid-web-service-construction-with.html' title='Rapid Web Service Construction with Groovy'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-2894284575627917883</id><published>2009-03-24T20:53:00.000-07:00</published><updated>2009-03-24T21:45:49.817-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>Exploring XML Using Haskell</title><content type='html'>I am trying to learn how to process XML using Haskell and I haven't found any "Hello World" tutorials on how to just access various nodes and attributes of an XML document using HaXml.&lt;br /&gt;&lt;br /&gt;The following is a transcript of a ghci session I had tonight (minus a handful of bloopers).&lt;br /&gt;&lt;br /&gt;I'm not a Haskell expert so expect less than stellar Haskell code.  My main purpose for writing this is to give others a jumping off point into HaXml.&lt;br /&gt;&lt;br /&gt;First I started ghci:&lt;br /&gt;&lt;blockquote&gt;tim@laptop:~$ ghci&lt;br /&gt;GHCi, version 6.10.1: http://www.haskell.org/ghc/  :? for help&lt;br /&gt;&lt;/blockquote&gt;Then I declared a String that held my XML document text (formatted to fit your screen):&lt;br /&gt;&lt;blockquote&gt;Prelude&gt; let xmlText = "&amp;lt;?xml version=\"1.0\"?&amp;gt;&amp;lt;order&amp;gt;&lt;br /&gt;&amp;lt;part number="\"&amp;gt;Hammer&amp;lt;/part&amp;gt;&lt;br /&gt;&amp;lt;part number="\"&amp;gt;Nail&amp;lt;/part&amp;gt;&lt;br /&gt;&amp;lt;/order&amp;gt;"&lt;/blockquote&gt;Before I can parse the XML, I'll need to import some of HaXml's libraries.  The :m +&lt;br /&gt;&lt;modulename&gt; command will do that for us:&lt;br /&gt;&lt;blockquote&gt;Prelude&gt; :m +Text.XML.HaXml&lt;br /&gt;Prelude Text.XML.HaXml&gt; :m +Text.XML.HaXml.Parse&lt;br /&gt;&lt;/blockquote&gt;Now I can parse the XML and extract just the root of the document:&lt;br /&gt;&lt;blockquote&gt;Prelude Text.XML.HaXml Text.XML.HaXml.Parse&gt; let (Document _ _ root _) = xmlParse "(No Document)" xmlText&lt;br /&gt;&lt;/blockquote&gt;Actually, no parsing has taken place yet.  xmlParse is lazy and will only parse the XML text when necessary.&lt;br /&gt;&lt;br /&gt;The first argument to xmlParse is "(No Document)".  That's just a dummy value that's used by HaXml for error reporting purposes.  If I had parsed XML from a file, I would have substituted the file name for the dummy value.&lt;br /&gt;&lt;br /&gt;Let's see what type the root has:&lt;br /&gt;&lt;blockquote&gt;Prelude Text.XML.HaXml Text.XML.HaXml.Parse&gt; :t root&lt;br /&gt;root :: Element Text.XML.HaXml.Posn.Posn&lt;/blockquote&gt;The combinators I'll be using expect a Content value not an Element.  So let's create a Content value from this Element.  But first we need to load another module:&lt;br /&gt;&lt;blockquote&gt;Prelude Text.XML.HaXml Text.XML.HaXml.Parse&gt; :m +Text.XML.HaXml.Posn&lt;br /&gt;&lt;/blockquote&gt;Having all these modules in the prompt is getting annoying.  Let's remove them:&lt;br /&gt;&lt;blockquote&gt;Prelude Text.XML.HaXml Text.XML.HaXml.Parse Text.XML.HaXml.Posn&gt; :set prompt "&gt; "&lt;br /&gt;&lt;/blockquote&gt;Now our prompt will just be the &gt; character followed by a space.&lt;br /&gt;&lt;br /&gt;And now we can wrap the Element value in a Content value:&lt;br /&gt;&lt;blockquote&gt;&gt; let rootElem = CElem root noPos&lt;br /&gt;&gt; :t rootElem&lt;br /&gt;rootElem :: Content Posn&lt;br /&gt;&lt;/blockquote&gt;To select nodes in the XML tree we can use the tag function:&lt;br /&gt;&lt;blockquote&gt;&gt; :t tag&lt;br /&gt;tag :: String -&gt; Content i -&gt; [Content i]&lt;br /&gt;&lt;/blockquote&gt;It takes a String and a Content value (our document root) and returns potentially multiple Content values (each node whose tag name matched the supplied String).&lt;br /&gt;&lt;br /&gt;Let's see the type of value we get when we supply tag with a String:&lt;br /&gt;&lt;blockquote&gt;&gt; :t tag "order"&lt;br /&gt;tag "order" :: Content i -&gt; [Content i]&lt;br /&gt;&lt;/blockquote&gt;No surprise there if you're familiar with currying.&lt;br /&gt;&lt;br /&gt;And let's see the type of the value returned from tag when both a String and a Content value are supplied:&lt;br /&gt;&lt;blockquote&gt;&gt; :t tag "order" rootElem&lt;br /&gt;tag "order" rootElem :: [Content Posn]&lt;br /&gt;&lt;/blockquote&gt;How many element names matched "order"?&lt;blockquote&gt;&gt; length $ tag "order" rootElem&lt;br /&gt;1&lt;/blockquote&gt;You can search for tags within tags using the /&gt; function.  Notice that the chained functions below have the same type as the tag function:&lt;br /&gt;&lt;blockquote&gt;&gt; :t tag "order" /&gt; tag "part"&lt;br /&gt;tag "order" /&gt; tag "part" :: Content i -&gt; [Content i]&lt;br /&gt;&lt;/blockquote&gt;Let's search for "part" tags within the "order" tag and see how many nodes we get (it should be 2 because we have 2 orders in our XML text):&lt;br /&gt;&lt;blockquote&gt;&gt; length $ tag "order" /&gt; tag "part" $ rootElem&lt;br /&gt;2&lt;br /&gt;&lt;/blockquote&gt;Let's grab just the first "part" element and examine its type:&lt;br /&gt;&lt;blockquote&gt;&gt; let firstPart = (tag "order" /&gt; tag "part" $ rootElem) !! 0&lt;br /&gt;&gt; :t firstPart&lt;br /&gt;firstPart :: Content Posn&lt;br /&gt;&lt;/blockquote&gt;Great. We now have a single XML element in firstPart.&lt;br /&gt;&lt;br /&gt;Let's poke around the internals of firstPart.   To do that we'll pattern match on firstPart:&lt;br /&gt;&lt;blockquote&gt;&gt; let (CElem (Elem name attributes _) _) = firstPart&lt;br /&gt;&lt;/blockquote&gt;Now we can look at the part elements tag name:&lt;br /&gt;&lt;blockquote&gt;&gt; name&lt;br /&gt;"part"&lt;br /&gt;&lt;/blockquote&gt;And see how the attributes are stored:&lt;br /&gt;&lt;blockquote&gt;&gt; :t attributes&lt;br /&gt;attributes :: [Attribute]&lt;br /&gt;&lt;/blockquote&gt;That makes sense since an element can have multiple attributes.&lt;br /&gt;&lt;br /&gt;We know that this node just has one attribute so let's grab it:&lt;br /&gt;&lt;blockquote&gt;&gt; let (attrName, _) = attributes !! 0&lt;br /&gt;&gt; attrName&lt;br /&gt;"number"&lt;br /&gt;&lt;/blockquote&gt;The second part of an Attribute is an AttValue which is a list of "Either String Reference" values.  I'm not sure why this is.  I thought that a single attribute could only have one value.  Perhaps not?&lt;br /&gt;&lt;br /&gt;Let's grab the first attribute's AttValue:&lt;br /&gt;&lt;blockquote&gt;&gt; let (_, attrValue) = attributes !! 0&lt;br /&gt;&gt; :t attrValue&lt;br /&gt;attrValue :: AttValue&lt;br /&gt;&lt;/blockquote&gt;And now we'll grab the list of Either values and store the first one in "firstAttrValue":&lt;br /&gt;&lt;blockquote&gt;&gt; let (AttValue (firstAttrValue:_)) = attrValue&lt;br /&gt;&gt; :t firstAttrValue&lt;br /&gt;firstAttrValue :: Either String Reference&lt;br /&gt;&lt;/blockquote&gt;Now we'll try to access the attribute String:&lt;br /&gt;&lt;blockquote&gt;&gt; let (Left value) = firstAttrValue&lt;br /&gt;&gt; value&lt;br /&gt;"101"&lt;br /&gt;&lt;/blockquote&gt;Sure enough, the first "part" has a part number of "101".&lt;br /&gt;&lt;/modulename&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-2894284575627917883?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/2894284575627917883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=2894284575627917883' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2894284575627917883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2894284575627917883'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2009/03/exploring-xml-using-haskell.html' title='Exploring XML Using Haskell'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-6562355801043457180</id><published>2009-02-25T05:54:00.000-08:00</published><updated>2009-02-25T06:49:51.232-08:00</updated><title type='text'>REST and Déjà vu</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;REST&lt;/a&gt; is getting a lot of attention.  I'm still working my way through "&lt;a href="http://oreilly.com/catalog/9780596529260/"&gt;RESTful Web Services&lt;/a&gt;" by Leonard Richardson and Sam Ruby.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As I understand REST, if I want to access a resource I can use the GET method and I will receive a representation of that resource that includes that resource's data.  If I want to update the resource, I use the PUT method to "save" the resource's new data.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What does that remind me of?  Think.  Think.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ah yes!  My early days of coding in C.  I would get a struct-full of data from somewhere, change one or more members, and then call some method that persisted those changes.  The struct I was changing just contained data and had no behavior. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Object Orientation&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Later on I learned how to &lt;a href="http://en.wikipedia.org/wiki/Encapsulation_(computer_science)"&gt;encapsulate&lt;/a&gt; the struct's data and use functions to provide behavior for the struct.  Then I learned about &lt;a href="http://en.wikipedia.org/wiki/Object-oriented_programming"&gt;Object Orientation&lt;/a&gt; (OO).  With OO, as a user of an object, I don't need to know anything about the object's data, what its members mean, valid combinations of data, etc.  I let the object handle all that stuff.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I know OO isn't a panacea &lt;i&gt;and&lt;/i&gt; that it isn't universally accepted &lt;i&gt;and&lt;/i&gt; that those who do accept it rarely agree on what it means or how to do it right.  But hasn't it taught us that encapsulation is good?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I do know that I don't want to go back to programming like I did in my early days of C programming.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Un-RESTful Web Services&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm not saying that we need to start exposing all our objects via URIs.  Objects typically have chatty interfaces (lots of fine-grained messages passed to the object) and chatty doesn't scale very well.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I do think that the Facade design pattern can be used to keep the interfaces more chunky (fewer, but coarser-grained messages passed to the facade) and our systems performing better.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is the approach that many web services use today.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hackable URLs&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;REST provides hackable URLs:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;   GET /book  (returns all books)&lt;/div&gt;&lt;div&gt;   GET /book/123  (returns the representation of book #123)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's very cool.  There's nothing preventing us from using hackable URLs in web services.  In fact all you Smalltalkers and Objective-Cers might feel right at home with URLs like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;   /book/123/delete  (deletes book #123)&lt;/div&gt;&lt;div&gt;   /book/124/loanToUser/432 (loans book #124 to user #432).&lt;/div&gt;&lt;div&gt;   /books/addTitle/Object+Thinking/copies/4/branch/Central (adds 4 copies of a book to one branch's inventory)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Encapsulation&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another reason why we use objects is because our object's representation, the very thing that REST makes public, might change and we don't want the user of our object to be affected by a change to our object's internals.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'll keep reading the RESTful Web Services book and hopefully I'll find out that I've misunderstood everything and that REST really is a step forward (or at least sideways) and not a step backwards.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-6562355801043457180?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/6562355801043457180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=6562355801043457180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6562355801043457180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6562355801043457180'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2009/02/rest-and-deja-vu.html' title='REST and Déjà vu'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-7601584929473091646</id><published>2008-12-29T15:18:00.000-08:00</published><updated>2008-12-29T16:16:36.768-08:00</updated><title type='text'>Single Responsibility Principle</title><content type='html'>I really do like what Robert C. Martin has to say about &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;OO&lt;/span&gt;&lt;/span&gt; but I just don't agree with his position on the Single Responsibility Principle.  It sounds like a good principle but then when I try to apply it in my mind,  problems arise.&lt;br /&gt;&lt;br /&gt;Let's look at a few of the classes he ends up with in his &lt;a href="http://www.objectmentor.com/resources/articles/srp.pdf"&gt;paper on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;SRP&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;.  The Connection interface has two methods: dial (which takes a string) and hangup.   Does this class really have only one reason to change?  No, there are still a number of reasons why this class might need to change.  There might be different ways of hanging up ("politely" for valid connections and abruptly for would-be hackers).  There might be different ways of dialing (with or without the speaker, supplying credentials, selecting a protocol, specifying minimum modem speed, etc.).  There might be modems that never hang up.&lt;br /&gt;&lt;br /&gt;I would posit that most classes have more than one reason for change.   Here are a few examples.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rectangle&lt;/span&gt; - the data types for the coordinates may change (16-bit to 32-bit), we may want polar coordinates instead of &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;Cartesian&lt;/span&gt;.  We may even want non-euclidean rectangles.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;String&lt;/span&gt; - The character set may need to change.  The storage mechanism may change (e.g. list, array, linked blocks of memory).  The allocation scheme may change.&lt;br /&gt;&lt;br /&gt;Just as easily as someone can say there is only one reason for a class to change, someone can find out multiple reasons for that same class to change (with very few exceptions).  It's quite subjective.&lt;br /&gt;&lt;br /&gt;If you &lt;span style="font-style: italic;"&gt;could&lt;/span&gt; split all your classes into single responsibility objects, you'd have a huge number of classes that each did very little.  To do anything useful, you would need to enlist the help of many classes.  This makes for poor comprehension of the system and poor usability.&lt;br /&gt;&lt;br /&gt;I want there to be a one to one mapping between concepts and classes.  If I have a concept of a file, and I want to read and write from a file, I will expect there to be a file object with read and write methods.  If I have to create input streams and output streams and file-opener objects, I will not enjoy the experience.  I want a file object.  I don't care if, behind the scenes the file is using an input stream and a output stream and a file-opener.  I just don't want to see them or need to know about them.&lt;br /&gt;&lt;br /&gt;With this one concept per class approach, there is a greater chance of complexity if precautions aren't taken.  To combat that complexity, I would consider breaking up the main concept into &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;sub concepts&lt;/span&gt; (e.g. input, output, seeking, etc.) and then coding each &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;sub concept&lt;/span&gt; as a separate class and then hide that class behind the facade of the main concept's class.&lt;br /&gt;&lt;br /&gt;This approach also helps with testing.  If each of the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_5"&gt;sub concept&lt;/span&gt; classes can be mocked and injected into the main concept's class, the class is easy to use and easy to test.&lt;br /&gt;&lt;br /&gt;You still need to guard against combining incompatible concepts into one class (e.g. file management with searching directories) mostly to avoid confusing the user.  Remember that class size and complexity can be managed by decomposing the main concept's class into other classes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-7601584929473091646?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/7601584929473091646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=7601584929473091646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7601584929473091646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7601584929473091646'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/12/single-responsibility-principle.html' title='Single Responsibility Principle'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-551835559926161681</id><published>2008-05-12T13:57:00.000-07:00</published><updated>2008-05-12T14:19:03.510-07:00</updated><title type='text'>Measuring Talkativeness With Big O Notation</title><content type='html'>In addition to its commonly known uses, &lt;a href="http://en.wikipedia.org/wiki/Big_O_notation"&gt;Big O Notation&lt;/a&gt; can also useful for describing a person's talkativeness.  Given the number of words you say to a person, their Big O factor tells you how long their response will probably be.&lt;br /&gt;&lt;br /&gt;The stereotypical male's Big O factor is O(1).  Regardless of what you say to him, you get a constant response (which may or may not be a grunt).&lt;br /&gt;&lt;br /&gt;A cooperative conversation would be some where in the neighborhood of O(n) meaning that both parties are contributing equal amounts.&lt;br /&gt;&lt;br /&gt;Then we get to the chatterbox who has a Big O factor of O(n^3).  I get a little nervous when I encounter a person with this kind of Big O factor.  I know that even if I grunt, that will spawn a long and drawn out discussion on some topic.&lt;br /&gt;&lt;br /&gt;I used to know a guy who was somewhere around O(n^n!).  I really dreaded seeing him.&lt;br /&gt;&lt;br /&gt;What gets dangerous is when you have two O(n^n) (or worse) folks talking with each other.  Each one's response is amplified by the others until they're both talking over each other and they pass out from buffer overflows.&lt;br /&gt;&lt;br /&gt;I've been too general up too this point.  I know that based on the topic of conversation, I have different Big O factors.  Here is a list of topics and my Big O factor for each topic.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Sports - O(1) (yes, I will grunt).&lt;/li&gt;&lt;li&gt;Politics - O(n/2)&lt;/li&gt;&lt;li&gt;Computers - O(n^2)&lt;/li&gt;&lt;li&gt;Clothing, Shoes or Purses - O(1)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-551835559926161681?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/551835559926161681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=551835559926161681' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/551835559926161681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/551835559926161681'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/05/measuring-talkativeness-with-big-o.html' title='Measuring Talkativeness With Big O Notation'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-6186212835669890285</id><published>2008-05-01T07:43:00.001-07:00</published><updated>2008-05-01T08:09:22.811-07:00</updated><title type='text'>SharePoint : The Perfect Storm</title><content type='html'>Wikipedia defines a &lt;a href="http://en.wikipedia.org/wiki/Perfect_storm"&gt;perfect storm&lt;/a&gt; as "the simultaneous occurrence of events which, taken individually, would be far less powerful than the result of their chance combination." &lt;br /&gt;&lt;br /&gt;Rather than events, in the case of SharePoint, I see the elements of the perfect storm being conditions.  Those conditions are:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SharePoint is widely accepted by CEOs, CTOs, architects, and users all around.  SharePoint's user experience is very nice for the most part.  I think that the product brings a lot of value to users.  This is a good thing.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SharePoint does a lot just out of the box.  It has all sorts of useful templates for sites and it has common workflows.  However, beyond a certain point (as with most if not all software) SharePoint cannot do what you want without customizing it with managed code (C#, VB.NET, etc.).  This too is a good thing.&lt;/li&gt;&lt;li&gt;SharePoint's developer experience is terrible.  I won't &lt;a href="http://timjstewart.blogspot.com/2008/03/microsoft-sharepoint-development-and.html"&gt;go&lt;/a&gt; &lt;a href="http://timjstewart.blogspot.com/2008/04/sharepoint-one-question-personality.html"&gt;into&lt;/a&gt; &lt;a href="http://codebetter.com/blogs/jeffrey.palermo/archive/2007/09/13/sharepoint-is-not-a-good-development-platform.aspx"&gt;details&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;So on the one hand you have CEOs, CTOs, and architects pushing for the use of SharePoint in the company, and on the other hand you've got a terrible developer experience.  The eventual result is a shortage of SharePoint developers and an increased demand for them.&lt;br /&gt;&lt;br /&gt;Will enough SharePoint developers leave SharePoint that Microsoft will be pressured into improving the developer experience?  Or will there always be enough SharePoint developers to squeak by?&lt;br /&gt;&lt;br /&gt;CTOs and CEOs who select SharePoint and need to customize it might start feeling the effects of this perfect storm when they have a harder time hiring and retaining developers, and then have to pay them more.&lt;br /&gt;&lt;br /&gt;If you are in the software development business for the money, SharePoint development could be a great cash cow.  &lt;span style="font-size:78%;"&gt;The only problem is that you have to develop in SharePoint.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The next time you hear a technology is hot, you may want to find out why the technology is hot.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-6186212835669890285?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/6186212835669890285/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=6186212835669890285' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6186212835669890285'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6186212835669890285'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/05/sharepoint-perfect-storm.html' title='SharePoint : The Perfect Storm'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-6582163482356003062</id><published>2008-04-29T20:32:00.000-07:00</published><updated>2008-04-29T22:03:56.440-07:00</updated><title type='text'>The Forces of Characterization and Cohesion</title><content type='html'>Often times the first stage of enlightenment is when an original and revolutionary idea comes to me and grabs my attention.  In most of those cases, the second stage of enlightenment is when I realize that I had actually heard that idea from someone else.&lt;br /&gt;&lt;br /&gt;Regarding my latest "enlightenment", in the area of class names, I can't remember all of the sources of inspiration that came together but I experienced it while I was reading Kent Beck's book "&lt;a href="http://www.amazon.com/Implementation-Patterns-Addison-Wesley-Signature-Kent/dp/0321413091"&gt;Implementation Patterns&lt;/a&gt;".  The book is a collection of principles that promote improved code readability.&lt;br /&gt;&lt;br /&gt;While reading about the importance of selecting names for classes, a couple of principles that I had heard before came together into a single picture.&lt;br /&gt;&lt;br /&gt;That picture is made up of two forces.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Force of Characterization&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first is the Force of Characterization.  It exists between a class' name and the class' code.  If, and only if, the class' name properly characterizes what the class does, the Force of Characterization is in harmony.&lt;br /&gt;&lt;br /&gt;For example, if the class' name is Account and the code for the Account class does currency conversion, the name Account is a mis-characterization of the class' code.&lt;br /&gt;&lt;br /&gt;The Force of Characterization moves you to to examine the fit between the class' name and what the methods do and, where the fit is bad, it causes you to adjust either the name or what the methods do to bring the Force of Characterization into balance.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Force of Cohesion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The second is the Force of Cohesion.  Cohesion exists in a class' methods to the extent that the class' methods work together for a single purpose.&lt;br /&gt;&lt;br /&gt;If some of Account's methods provide account related operations (e.g. deposits, withdrawals), and other methods perform currency conversion, the methods are not cohesive.&lt;br /&gt;&lt;br /&gt;The Force of Cohesion moves you to examine the class' methods and how well they work together to a single end.  Bringing harmony to the Force of Cohesion is done by moving methods and perhaps data from one class to another.  It may also involve splitting up a single method into multiple methods.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Interplay Between the Forces&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Where this gets interesting is when these two forces start interacting with each other.&lt;br /&gt;&lt;br /&gt;As you change a class' name, you may be changing its purpose.  For example, changing the name of a class from CustomerInfo to Account significantly changes the expectations that a user would have for the class' code.&lt;br /&gt;&lt;br /&gt;Because the class' methods should be acting towards one purpose (the class' single purpose), changing the name of the class can affect the cohesiveness of the class' methods.  The single purpose that the class' methods were working towards before the class was renamed might have been redefined into two or more purposes.&lt;br /&gt;&lt;br /&gt;In other words, when you change the name of a class in an attempt to harmonize the Force of Characterization you may temporarily introduce disharmony with respect to the Force of Cohesion.  The converse of this is also true.&lt;br /&gt;&lt;br /&gt;Sometimes a disharmony in one force can be resolved without introducing disharmony in the other force.  However, I imagine these two forces occasionally going through cycles of harmony and disharmony, in and out of phase with one another, until both forces are in harmony, and a stable state has been reached.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;Changing a class' name can move you to change the class' methods to restore harmony in one of the two forces.&lt;/li&gt;&lt;li&gt;A class' name is important when adding features; it helps you answer the question, "Does this method/data member belong in this class?"   If you achieve harmony between the two forces, the class name will be a helpful guide as you read and maintain the class' code.&lt;/li&gt;&lt;li&gt;Changing a class' name may prompt you to rename methods to be more consistent with the name.&lt;/li&gt;&lt;li&gt;A class name that is a good characterization of the class' methods can actually assist you in maintaining the cohesiveness of the class by making un-cohesive code more obvious.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;Question(s):&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;Are there other forces that interact with class names and cohesion in interesting ways?&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-6582163482356003062?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/6582163482356003062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=6582163482356003062' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6582163482356003062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6582163482356003062'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/forces-of-characterization-and-cohesion.html' title='The Forces of Characterization and Cohesion'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-8742860168757483619</id><published>2008-04-24T14:32:00.000-07:00</published><updated>2008-04-24T18:59:47.394-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='three-tiered architecture'/><title type='text'>A Different Perspective on Web Applications</title><content type='html'>Notice that I said this perspective is different.  I intentionally left out words like: smart, useful, good, and many other positive adjectives.&lt;br /&gt;&lt;br /&gt;My goal for taking this perspective is to see if it fits, what problems it solves (or creates), if it makes reasoning about or building web applications any easier.  The good thing about perspectives is that you can try them on, look around, and then take them off (or even discard them).&lt;br /&gt;&lt;br /&gt;The perspective that I'm taking &lt;span style="font-style: italic;"&gt;off&lt;/span&gt; for this post is the one that states that a web application extends from the user in front of their browser all the way back to the data layer.  That perspective is nice and has been around for a while now.  But it has some rough edges that I'm trying to smooth out.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Rough Edges&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1) Data Validation is spread throughout all three layers of a three-tiered web application architecture.  I wrote about this &lt;a href="http://timjstewart.blogspot.com/2008/04/i-have-not-had-much-experience-with.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;2) Presentation Layer activities are performed in two places: in the browser via JavaScript, CSS, HTML, etc. and on the server when the HTML is dynamically generated (e.g. JSP, PHP, etc.).&lt;br /&gt;&lt;br /&gt;Perhaps these rough edges cannot be avoided and all my attempts to do so will fail.    Maybe I'm the rough edge and I just need to accept that the nature of the web requires that similar things need to happen in different places.  Or maybe I can just change the way I look at the problem so that the rough edges disappear.&lt;br /&gt;&lt;br /&gt;Here is the different perspective.  What if we equate a web application to a standalone desktop application like such:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Selecting the Application to Run&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To start a desktop application, you run a program at a certain location (its path) with optional arguments&lt;br /&gt;&lt;br /&gt;To start a web application, you enter a certain location (its URL) into your browser with optional arguments.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Application Start Up&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When you start a desktop application, one or more resources are loaded from the disk into memory, a user interface is presented, and an event loop is entered.&lt;br /&gt;&lt;br /&gt;When you start a web application, one or more resources are loaded from the web server into the browser, a user interface is presented, and an event loop is entered.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Additional Resources&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;As the desktop application is asked to do different things, it may load additional resources (e.g. user interface elements, XML files, DLLs, etc.) from the disk.&lt;br /&gt;&lt;br /&gt;As the web application is asked to do different things, it may load additional&lt;br /&gt;resource (e.g. HTML, JavaScript, CSS, images, etc.) from the web server.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Changing State&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The desktop application user wants to save their changes so the application the writes the changes to disk.&lt;br /&gt;&lt;br /&gt;The web application user wants to save their changes so the application sends the changes to the web server.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;After drawing these parallels, would you say that a Desktop Application extends from the user in front of the screen all the way to the disk?  Probably not.  Yes, the disk is involved, but that's not part of your application proper.&lt;br /&gt;&lt;br /&gt;So could we say that a web application starts at the user in front of the browser and ends inside the browser?&lt;br /&gt;&lt;br /&gt;Is that too much of a stretch?   Can we really equate the Internet, our web servers, and back end databases all to a storage device?  I'm going to try.  Maybe the analogy will work, maybe not.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Implications&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A number of interesting things happen once we say that a web application is just what is going on inside the browser:&lt;br /&gt;&lt;br /&gt;1) There are no more tiers to think about on the browser side (see also &lt;a href="http://en.wikipedia.org/wiki/Tautology"&gt;Tautology&lt;/a&gt;).  Perhaps we can simply adopt a &lt;a href="http://en.wikipedia.org/wiki/Model-view-controller"&gt;Model/View/Controller&lt;/a&gt; approach in the browser.  It's perfectly okay to have data validation in an MVC application so I don't need to worry about spreading data validation through out all three tiers (yes, I am totally ignoring the web server and database layer for now).  The browser is not self-sufficient; just as the desktop application loads resources from disk, the browser application will load resources from the web server.&lt;br /&gt;&lt;br /&gt;2) The web server becomes less user-serving and more application-serving.  A page served by the web server is not as much a page that the user will see as as it is some user interface resource that is loaded by the application.  The difference is subtle but I'm going to note it anyway.  Perhaps it's important.&lt;br /&gt;&lt;br /&gt;3) The web server gives up much of the control it had once we start putting more focus on the browser as the web application.  Many web server applications of old carefully created their HTML pages so that every link and button would initiate the proper request back to the server.  If the browser is the web application, the JavaScript code can play a much larger role in deciding what resources to request.&lt;br /&gt;&lt;br /&gt;I have really tightened my focus to the browser client and have forgotten all about the web servers, and database servers.  In doing so, I've seen some nice properties emerge on the client side.   For one, I can reason about the client in isolation.  But have I created a terrible mess on the server side?  Let's see.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What Does the Server Look Like Now?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As I start this section, I've isolated the browser client and abstracted away the rest of the application.  Now I've got to deal with the Application Layer and the Data Layer.  I'm starting to wonder if my attempt to gain a different perspective on three-tiered architecture will land me right back at a three-tiered architecture.&lt;br /&gt;&lt;br /&gt;Let me do a roll call to see what we have left on the server.&lt;br /&gt;&lt;br /&gt;Presentation Layer.  Check.  Granted it's not really presenting things to the user (as I pointed out earlier).&lt;br /&gt;&lt;br /&gt;Application Layer.  Check.  But couldn't we put all of the Application Layer on the client?  Yes we could, but should we.  Browsers with good debuggers allow users to modify the DOM and the JavaScript environment.  As a safety precaution, we need some code that the user can't tamper with.&lt;br /&gt;&lt;br /&gt;Data Layer.  Check.  We haven't gotten rid of that either.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I tried on a different perspective.  At first it seemed promising, and then the three tiers appeared again on the server side. &lt;br /&gt;&lt;br /&gt;In addition, the rough edges remain although the presentation rough edge is slightly different as we have two different parties we're presenting to (i.e. the browser application and the user).&lt;br /&gt;&lt;br /&gt;I like the way that the client looked in this perspective.  The only way to see if it really works though is through using this perspective to develop some web applications.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-8742860168757483619?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/8742860168757483619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=8742860168757483619' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/8742860168757483619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/8742860168757483619'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/different-perspective-on-web.html' title='A Different Perspective on Web Applications'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-8016471492650518617</id><published>2008-04-21T14:50:00.000-07:00</published><updated>2008-04-21T16:14:17.845-07:00</updated><title type='text'>Objects and Data Validation</title><content type='html'>I've written a lot of objects that do data validation but I have yet to come up with a standard approach to data validation for objects.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;When should the validation occur?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have usually taken the approach that as soon as something goes wrong, I want to know about it.  If you call a setter method passing in invalid data, I want to catch it immediately and reject it by throwing an exception.&lt;br /&gt;&lt;br /&gt;Ken Pugh, in his book &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0596008740"&gt;Prefactoring&lt;/a&gt; mentions the use of specific data types.  He would say that your setPhoneNumber() method should not take a string but it should take a PhoneNumber object.  The PhoneNumber class' constructor would parse whatever string you tried to initialize it with and throw an exception if you didn't pass it a proper phone number.  In this way, you can't even pass an invalid phone number to setPhoneNumber().&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Delayed Data Validation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are some cases where delayed data validation is the only way to go.  Consider a very contrived but simple class whose "lower" attribute must be the lower case version of its "upper" attribute.  If "lower" is 'a' then "upper" must be 'A'.  If the class provides only setLower(char c) and setUpper(char c) these methods cannot do data validation.  Either the class must supply a setBoth(char upperC, char lowerC) method or there must be a way to delay the data validation.&lt;br /&gt;&lt;br /&gt;A less contrived example would be a Location object that has a City and a State property.  If the object tries to make sure that the City value is always a city in the State value and that the State value always has a city by the name of the City value, users will find it difficult to use.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Not A City&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's try something.  If you had a special City value (e.g. NaCity resembling NaN for not a number) and a special State value (NaState) and setting the City would always set the State to NaState and vice versa, the validation could be simplified.  If the City value is NaCity don't validate it.  Hmm... but now you can have locations that don't contain City or State information.  That doesn't sound very valid.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Try To Be More Accepting&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let me make things a little more complicated.  Alan Cooper in his book "&lt;a href="http://www.amazon.com/About-Face-Essentials-Interface-Design/dp/1568843224"&gt;About Face&lt;/a&gt;" talks about data validation in the user interface.  He thinks that a user should be able to enter incomplete information.  Why should you have to discard your work if you don't have every required field filled in?  Perhaps data validation should only be done in select situations?  For example, I should be able to set attributes in my Customer object to whatever the data types will allow and save that invalid data.  But when I want to send out some invoices to my customers, I should only send out invoices to customers that pass data validation.  That way, I'm not sending mail to Fooville, or to Mars.  This approach would probably require some report or view that showed all customers who were in an invalid state.  That way folks can keep an eye on all of the Customers they can't yet bill.&lt;br /&gt;&lt;br /&gt;Reporting what is actually wrong might involve a wee challenge.  A Customer object might fail validation due to one of the Customer's aggregated objects.  It's up to the programmer to make sure that the source of the validation failure is reported correctly.&lt;br /&gt;&lt;br /&gt;Taking this on demand  approach to validation in the business logic tier and not in the data tier puts you in a bind.  Now you've got all of these invalid objects in memory, and you can't save any of them because of some database constraint.  The moral of the story is to synchronize your data validation approaches throughout all of the tiers of your application.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Changing My Mind&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The more I go on about data validation, the more I like the on demand approach.  The nicest thing about it is that it separates data modification from data validation.  You're always performing validation on stationary data.&lt;br /&gt;&lt;br /&gt;Now when I put on my user hat, I like to know if I've made a mess of something even if I can't fix it at the moment so flagging a Customer as invalid in the user interface is probably a good idea.&lt;br /&gt;&lt;br /&gt;There are some situations where this on demand approach to data validation won't work.  For example, if we were writing a code generator for Eclipse, and we allowed the user to create a class named "&lt;:^)" we would be doing them a disservice as the code would not compile and there may be many references to "&lt;:^)" that they would need to change.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;One Way of Data Validation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm sure there's not One True Way of Data Validation.  You may have a legacy database that has bullet proof constraints and is guarded by German Shepherd attack stored procedures.  You may have an object model that must be 100% valid at all times (e.g. Air Traffic Control systems, SDI, a super safe lethal injection device, etc.).&lt;br /&gt;&lt;br /&gt;For future projects, I think that I will start off with the on demand approach and see if that works.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Exercises Left to the Reader&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. Consider mixed models (e.g. strict data validation mixed with an on demand validation approach).  Would the mixture of data validation models be too confusing?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-8016471492650518617?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/8016471492650518617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=8016471492650518617' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/8016471492650518617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/8016471492650518617'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/objects-and-data-validation.html' title='Objects and Data Validation'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-7094633105554366466</id><published>2008-04-21T14:25:00.001-07:00</published><updated>2008-04-21T14:50:17.400-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='three-tiered architecture'/><title type='text'>In a Three-Tiered Architecture Where Should Data Validation Go?</title><content type='html'>I have not had much experience with three-tiered architectures so I'm working through some of the basic concepts that are tripping me up.&lt;br /&gt;&lt;br /&gt;Right now I'm considering where data validation should take place.  That sounds like something that would fit in the business logic tier.  But there are benefits of putting some form of data validation in each of the three tiers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Presentation Tier&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When writing a web application, if you can avoid a round trip, you might want to.  You might not want to avoid the round trip if:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;the cost (development or throughput) of avoiding the round trip is prohibitive.&lt;/li&gt;&lt;li&gt;the latency is expected to be low (e.g. intranet applications).&lt;/li&gt;&lt;/ul&gt;One way of avoiding that round trip is by performing some of the data validation on the client-side.&lt;br /&gt;&lt;br /&gt;Most of the data validation I've encountered is very narrowly focused.  For example, the user's name is validated separately from the user's age.  I don't think I've ever seen cross-field validation (e.g. "A customer with status X must have a account balance below Y.").  Does this suggest that the client-side validation should just be a first line of defense against invalid data?&lt;br /&gt;&lt;br /&gt;It seems like data validation is at home in the Presentation Tier.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Business Logic Tier&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is where data validation naturally belongs (right?).  You've got a bunch of Customer objects that are being manipulated in memory.  When do you want to know that your Customer data is invalid?  When you try to save the Customer data to the database?  Or would you rather know that the Customer data is invalid the moment you attempt to modify a Customer object in an invalid way?  Personally, I like knowing that something went wrong as soon as it goes wrong.&lt;br /&gt;&lt;br /&gt;It seems like data validation is at home in the Business Logic Tier too.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Data Tier&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What good DBA would ever trust all clients of his/her data to keep that data in a valid state at all times?  Enter database constraints designed to maintain the data's validity.  The database constraints are the last line of defense for data validation.&lt;br /&gt;&lt;br /&gt;It seems like data validation is at home in the Data Tier too.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Questions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The validation performed in the presentation tier is probably different from the validation performed in the data tier and the business logic tier.  How does one get a good idea of what valid data is if the validation is spread over three tiers?&lt;br /&gt;&lt;br /&gt;It would be useful if I could specify what makes the data valid in one place in the form of multiple validation rules and then for each validation rule specify the tiers where they should be enforced.  It seems like this would be a fairly challenging problem to solve without some sort of framework.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-7094633105554366466?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/7094633105554366466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=7094633105554366466' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7094633105554366466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7094633105554366466'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/i-have-not-had-much-experience-with.html' title='In a Three-Tiered Architecture Where Should Data Validation Go?'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-2909297051263688822</id><published>2008-04-19T06:41:00.000-07:00</published><updated>2008-04-19T09:43:32.116-07:00</updated><title type='text'>How JavaScript Stirs Up The Three-Tier Architecture</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;A Place for Everything and Everything in it's Place&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;When it comes to designing web applications I thought I knew where everything should go. I thought that business logic should go in the "logic tier", and that user interface stuff should go in the "presentation tier", and that the data would be stored in the "data tier" (see &lt;a href="http://en.wikipedia.org/wiki/Three-tier_(computing)"&gt;three-tier Architecture&lt;/a&gt;). If I had been asked, "Where does JavaScript fit into all this?", I would have said that it is useful for providing basic client-side validation a la, "Customer name cannot be blank.".&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Enter JavaScript&lt;/strong&gt;&lt;/p&gt;Within in the last six months or so, I've discovered two things that have shaken up my three-tiered perspective.&lt;br /&gt;&lt;br /&gt;First, JavaScript (or at least the way it is being used) has matured quite a bit. Now those who have been following JavaScript carefully for a while will be able to calculate how deep my head has been in the sand from this last statement.&lt;br /&gt;&lt;br /&gt;Second, a number of powerful JavaScript libraries/toolkits have been produced (e.g. &lt;a href="http://jquery.com/"&gt;JQuery&lt;/a&gt;, &lt;a href="http://dojotoolkit.org/"&gt;Dojo&lt;/a&gt;, &lt;a href="http://script.aculo.us/"&gt;Script.aculo.us&lt;/a&gt;, &lt;a href="http://prototypejs.org/"&gt;Prototype&lt;/a&gt;, &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt;, etc.). I'm sure that some of these libraries have been around for a long time, but I am only discovering them now. And I'm having a great time playing with them.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The Power of JavaScript&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;These JavaScript libraries go a lot further than just telling the user that the "Customer name cannot be blank." They provide serious event handling, cool effects on top of JavaScript's ability to create objects with methods and properties. With all of these features, you could potentially move all three tiers of the three-tier architecture into the browser client. At least you could if you don't mind the total lack of persistence. If you want persistence, then you do have to communicate with a server (unless you find that storing your data in cookies works for your application).&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Where Does Everything Go Now?&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;So now I'm confused. I like being able to split things up into pieces and then put the pieces somewhere. If I try to split up my web application according to its tiers, I find that JavaScript can play in all three tiers although it's typically only used in the browser. So we have some dissonance between the physical tiers and how client-side JavaScript can be used to augment each of the three tiers:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JavaScript can create and manipulate objects just like the data tier.&lt;/li&gt;&lt;li&gt;JavaScript can run business logic on the client side. This can reduce round trips to the server.&lt;/li&gt;&lt;li&gt;JavaScript can present the data to the user in all sorts of ways.&lt;/li&gt;&lt;/ul&gt;When JavaScript deals with all three parts of the three-tier architecture some interesting results occur:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The logical tiers are now split across the physical tiers (the client and the various types of servers).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Code may be duplicated in different places in different languages. Customer validation in the client would be in Java while Customer validation on the business logic tier would be done in Java or C#. Copy/Paste Programming is bad but try to imagine Copy/Translate/Paste Programming.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Thanks to JavaScript debuggers that can be embedded in a browser, users can inspect, the DOM and make changes to it. This has a number of security implications. A JavaScript application can't always trust its own DOM. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Simplifying the Question&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Let me back up for a minute. Should JavaScript be used in all three tiers (on the client side)? I think that it's safe to say JavaScript should not generally be used in the client-side data tier. The data tier is all about persistence and JavaScript has some significant limitations in the persistence department. It's very clear that JavaScript is a very natural fit for use in the presentation tier. This leaves only the question of whether or not JavaScript should be used in the logic tier? And if so, how?&lt;/p&gt;&lt;p&gt;I think that JavaScript brings a lot of benefits to the client-side logic tier. Unfortunately it can only do so safely if the server mirrors that business logic and distrusts the client-side logic. Since JavaScript is so dynamic users can tamper with client-side code and make the business logic do anything they want.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Code Generation to the Rescue?&lt;/strong&gt;&lt;/p&gt;I wonder if code generation is a partial solution to this. The book, "&lt;a href="http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X"&gt;The Pragmatic Programmer&lt;/a&gt;" suggested that if code/data does need to be duplicated, then there should be one source representation of that code or data and all duplicates should be generated from it.&lt;br /&gt;&lt;br /&gt;The wonderful thing about JavaScript is that even if client-side code and server side code are generated from a single source, they will always be in synch because the client is always downloading the most recent version of the JavaScript.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I'll spend some more time thinking about this and then write up some thoughts. I'd be very interested in hearing how you approach this.&lt;br /&gt;&lt;br /&gt;Thanks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-2909297051263688822?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/2909297051263688822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=2909297051263688822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2909297051263688822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2909297051263688822'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/how-javascript-stirs-up-three-tier.html' title='How JavaScript Stirs Up The Three-Tier Architecture'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-7751424892130481892</id><published>2008-04-18T13:54:00.000-07:00</published><updated>2008-04-18T14:54:24.419-07:00</updated><title type='text'>The Free Stuff You Get From {Gr|R}ails</title><content type='html'>I'm learning &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; (before that it was &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt;). Up until recently, I've been really impressed by what these frameworks give you "for free": &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM&lt;/a&gt;, pages for performing &lt;a href="http://en.wikipedia.org/wiki/Create%2C_read%2C_update_and_delete"&gt;CRUD&lt;/a&gt; operations on the data, one or more application servers, etc. &lt;br /&gt;&lt;br /&gt;But as I consider the usability of the software that these frameworks give you for free, I start wondering if some of this free stuff is worth it.&lt;br /&gt;&lt;br /&gt;The more practical side of me has been confronting the side of me that was initially so giddy over the power and &lt;a href="http://en.wikipedia.org/wiki/Rapid_application_development"&gt;RAD&lt;/a&gt;-ness offered by these frameworks.&lt;br /&gt;&lt;br /&gt;Here's one recent exchange between my practical side and my giddy side...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Giddy Tim: &lt;/span&gt;So with just a few commands and some editing of a Customer.rb (or .groovy), I can show users a page that lists every Customer in the database!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Practical Tim:&lt;/span&gt; What kind of user wants to see every Customer in the database?  Sure if you're interested in one of the first Customers in the list, you might be happy with the list but what about every one else?  Everyone else has to some how get to the Customer they're interested in.  What your users probably want is a search feature so that they can search for a particular Customer.  They probably would like a list of the Customers that they deal with the most, you know, their favorites.  Or maybe they want to narrow the field by listing all Customers in a particular Category.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Giddy Tim: &lt;/span&gt;You've got some good points there.  At least I have an edit page that shows the Customer and a place where I can briefly list, but not edit or view the details of, the Customer's Orders.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Practical Tim:&lt;/span&gt; So you have to go to another screen to edit or view the Orders?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Giddy Tim:&lt;/span&gt; Yes, at least one screen.  There's the "View Order" page, then I click the "Edit" link and I'm taken to the "Edit Order" page.  Then when I'm done editing, I click "Save" and then I'm redirected to the "View Order" Page again.  Then, if I customize the Controller, I can have it redirect me back to the "Edit Customer" Page of the Customer whose Order I wanted to edit.  Even though the system knows that there is a one to many relationship between Customers and Orders there is still a one to one relationship when it comes to pages.  Each "Edit" page edits a single record in the database.  Simple, eh?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Practical Tim:&lt;/span&gt; With &lt;a href="http://jquery.com/"&gt;a powerful JavaScript library&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/AJAX"&gt;Ajax&lt;/a&gt; couldn't you easily allow the user to edit Customers and their Orders all from the same page?  That seems like a better user experience to me.  &lt;a href="http://en.wikipedia.org/wiki/Alan_Cooper"&gt;Alan Cooper&lt;/a&gt; in his book &lt;a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111"&gt;"About Face"&lt;/a&gt; says that it's a good idea to allow users to edit data where it's displayed.  It sounds like these frameworks create an unnecessary distance between editing and viewing, and part/whole relationships.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Giddy Tim:&lt;/span&gt; So to offer the users a good user experience, it sounds like I'll need to modify the automatically generated code extensively.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Practical Tim:&lt;/span&gt; Yep, see you around Giddy Tim!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Giddy Tim:&lt;/span&gt; Uh, just call me Tim.&lt;br /&gt;&lt;br /&gt;I will continue to use Grails, and Rails, and maybe even &lt;a href="http://merbivore.com/"&gt;Merb&lt;/a&gt;, but I will use them with open eyes knowing that once the frameworks have generated code for me, I've probably still got a lot of work ahead of me.&lt;br /&gt;&lt;br /&gt;P.S. I'm sure that the code generation engines can be improved to generate more usable interfaces (although they may need some hints and guidance from the programmers).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-7751424892130481892?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/7751424892130481892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=7751424892130481892' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7751424892130481892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7751424892130481892'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/free-stuff-you-get-from-grrails.html' title='The Free Stuff You Get From {Gr|R}ails'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-6919980254938009345</id><published>2008-04-10T08:11:00.000-07:00</published><updated>2008-04-10T08:15:07.895-07:00</updated><title type='text'>A Very Sad Book Title</title><content type='html'>&lt;a href="http://www.amazon.com/Managing-Catastrophic-Loss-Sensitive-Data/dp/1597492396"&gt;"Managing Catastrophic Loss of Sensitive Data"&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When I hear this title and think of who would buy the book, I imagine some guy with tear-stained cheeks, who has only recently arrived at the final stage of grief (acceptance), sheepishly approaching the checkout at the bookstore, getting ready to say, “It’s for a friend” to the cashier.&lt;span style=""&gt;  &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;o:p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/o:p&gt;I feel for this guy.&lt;o:p&gt;&lt;/o:p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-6919980254938009345?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/6919980254938009345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=6919980254938009345' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6919980254938009345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/6919980254938009345'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/very-sad-book-title.html' title='A Very Sad Book Title'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-1242921701986618773</id><published>2008-04-02T11:29:00.000-07:00</published><updated>2008-04-02T11:31:51.416-07:00</updated><title type='text'>The SharePoint One-Question Personality Test</title><content type='html'>&lt;strong&gt;Do you like developing in SharePoint?&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If you answered "yes"...&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You are not bothered by frequently performing repetitive tasks.     &lt;/li&gt;&lt;li&gt;You do not mind expending large amounts of energy in order to receive small rewards.     &lt;/li&gt;&lt;li&gt;You can handle large amounts of cognitive dissonance.     &lt;/li&gt;&lt;li&gt;You like swimming in uncharted, undocumented waters.     &lt;/li&gt;&lt;li&gt;You don't need constant reassurance that your code works (e.g. unit tests).&lt;/li&gt;&lt;/ul&gt;If you answered "no"...&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You prefer to automate any repetitive tasks.    &lt;/li&gt;&lt;li&gt;You want your energy investment to be close to the expected rewards for that investment.    &lt;/li&gt;&lt;li&gt;You like it when things are logical, orderly and, just make sense.    &lt;/li&gt;&lt;li&gt;You like navigating waters that have been mapped and documented.    &lt;/li&gt;&lt;li&gt;You like being constantly assured that your code works (e.g. continuous integration and unit tests).&lt;/li&gt;&lt;/ul&gt;Just a theory but I think that these two sets of answers align with two categories of people.  Those who answer "yes" seem to fit into the thrill-seekers category.  Those who answer "no" seem to fit into the more cautious category.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-1242921701986618773?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/1242921701986618773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=1242921701986618773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/1242921701986618773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/1242921701986618773'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/04/sharepoint-one-question-personality.html' title='The SharePoint One-Question Personality Test'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-7986224313090419126</id><published>2008-03-03T05:33:00.000-08:00</published><updated>2008-03-03T13:07:50.736-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SharePoint'/><title type='text'>Microsoft SharePoint Development and Tractor Pulls</title><content type='html'>If you don't know what a tractor pull is, you might want to check out &lt;a href="http://en.wikipedia.org/wiki/Tractor_pulling"&gt;Wikipedia&lt;/a&gt;. If you're a SharePoint developer, you are probably more familiar with tractor pulls than you might expect. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The basic concept of a tractor pull is that you attach a big weight on wheels to a vehicle and the vehicle starts moving forward. As time progresses the weight being towed shifts in such a way that it gets harder for the vehicle to tow it forward. After a while, the vehicle cannot even move.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So how is that like SharePoint development? If you do all your development in the production environment, then you probably aren't experiencing the "Tractor Pull Effect". There are other effects that you're more likely to encounter (e.g. the "Who deleted all of the Customers Data? Effect", or the "Users keep asking why the system is down Effect").&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But if you've carefully set up a Development, Test, and Production environment, you probably already know the "Tractor Pull Effect".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you need to take your changes that you made in Development and promote them to the Test environment, SharePoint tools only take you so far. Where I work, we've got some "extra special" tools written by a SharePoint genius that automate much of the promotion process. These tools are not perfect or automated (yet). &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even after these tools run, there is much work to be done to the Test environment to make it mirror the Development environment. Web Parts need to be reconnected, connection strings in charts need to be set to point to the Test database servers. Then the site needs to be manually checked to make sure that the promotion process didn't hiccup (which it does on occasion).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then when you want to deploy from Test to Production a different set of rules apply. The promotion process has a tendency to delete data (which is fine in a Test environment, right?). These different rules add complexity and additional effort because now you're redoing a lot of work in production that you did in Development.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div align="left"&gt;A Short Digression. Maybe every single list, site definition, and page you deploy to SharePoint is done via a SharePoint "feature" so you're not experiencing any of the problems I'm talking about. I've also done that style of development and it appears to be much more clean and reproducible. My frustration there is that if I want to add a link to a navigation area, I have to create a feature folder with two XML files in it and then install and activate that feature. That's a simple task. Creating a custom list took me days the first time I tried it. That is nowhere near agile. I would imagine that most SharePoint shops are somewhere between the do everything in the user interface approach and the do everything via a feature approach... Digression over.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;So the more features you add to your product, the more setup, configuration, and rework you end up doing as you promote your work from Development onward.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In a tractor pull, the weight eventually ceases all forward motion. I'm not looking forward to the point where we have so many features, that all of our forward motion ceases. Hopefully before that point, the "extra special" tools will work 100% of the time and they will be automated and I'll have nothing to complain about.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-7986224313090419126?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/7986224313090419126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=7986224313090419126' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7986224313090419126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7986224313090419126'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/03/microsoft-sharepoint-development-and.html' title='Microsoft SharePoint Development and Tractor Pulls'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-2122792643643851461</id><published>2008-01-31T04:50:00.000-08:00</published><updated>2008-01-31T05:18:47.326-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Alan Cooper'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='About Face'/><title type='text'>Database Constraints and Usability</title><content type='html'>&lt;div&gt;I've been playing with &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt; and have not been satisfied with the user experience of creating an object that is on the one side of a one-to-many relationship.  You must first create and save the object on the one side of the relationship, then edit it to add objects on the many side of the relationship.  Almost certainly, that is because a relational database cannot save the objects on the many side until the object on the one side has a row ID.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I don't like making the user suffer just to appease the relational model.  So what if I create and save the object on the one side at the moment the user requests to create one.  That way it has its row ID and the user can add objects on the many side.  Unfortunately, database constraints may prevent me from saving my object on the one side of the relationship.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I've read Alan Coopers' book, "About Face" and it has changed the way I view a number of things in the world of software.  It's been a while since I've read the book so maybe this post's topic was covered in "About Face".&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The facts:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Databases can have constraints to make sure that the data is "valid".&lt;/span&gt;  For example, in a customer billing application, a constraint on the customers table might say that all customers must have a mailing address.  This constraint would prevent you from entering a customer in the system that did not have an address.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Sometimes users don't have all the data and it would be inconvenient to force them to enter all the data or none of it.&lt;/span&gt;  Imagine filling out 80 fields in a form and then trying to save the data to the database only to be told that one field cannot be empty.  At that moment, you can either discard all of your work (potentially inconveniencing your customer who is providing the data to you) or entering some made up value into the form (possibly confusing the system or other people who interface with the system as in the case of a made up phone number or street address).&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;At the moment, I'm considering having a boolean/bit column in some of my tables whose name is 'valid'.  Then whenever a business object tries to persist to a row in a table, it performs validation and sets the 'valid' field to the result of the validation.  All other fields are also saved at that time. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The user can be notified that the data they entered was invalid and will be ignored by the system until one or more errors are fixed.  If you put a 'saved_by' field in the row that contains the user name of the last person that saved the row, you could periodically ask the user to correct their data.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Most of the queries in the system would only seek rows where the 'valid' field was true.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Database constraints are useful because they actually prevent the data from being invalid (as much as a constraint is able to anyway) and that is their strength.  Removing all constraints and using the 'valid' column does leave the database open to containing invalid rows whose 'valid' field is true, but only if you go around the business objects.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Perhaps database vendors will see this problem and introduce constraints that can allow invalid data to be stored as long as it's marked as invalid.  Maybe then my mail will stop going to 101 Nowhere Lane.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-2122792643643851461?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/2122792643643851461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=2122792643643851461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2122792643643851461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2122792643643851461'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/database-constraints-and-usability.html' title='Database Constraints and Usability'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-7425953941716377135</id><published>2008-01-19T14:21:00.001-08:00</published><updated>2008-01-19T14:23:16.391-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rules'/><category scheme='http://www.blogger.com/atom/ns#' term='random thoughts'/><category scheme='http://www.blogger.com/atom/ns#' term='object thinking'/><title type='text'>Random Thoughts and Questions</title><content type='html'>Some random thoughts and questions....&lt;br /&gt;&lt;br /&gt;If two objects of the same class have different rules, how did they get those different rules?  Was there some object factory that gave them different rules?   If other objects modify an object's rules, is that a violation of encapsulation?  If an object is the only entity allowed to modify its rules, that means that it must know about all possible rules it can have within the domain.  For some domain types (e.g. account types) where there is a closed set of kinds, this might not be a bad idea.  For open ended domain types (e.g. widgets) this could not possibly work.&lt;br /&gt;&lt;br /&gt;In the case of the Customer class, what would be involved when giving a Customer a discount?  We certainly need to specify and store the amount of the discount.  But do we also add a rule to the class?  Or was the rule there all along waiting for a discount attribute to be set?  Since rules may operate on attributes, it's important to keep them in sync.  If you have a rule that expects a discount attribute but no discount attribute is in your object's Description Object, your rule will fail or misbehave.&lt;br /&gt;&lt;br /&gt;Also it seems like a Description Object might encounter name collision issues.  Perhaps there should be namespaces within a Description Object?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-7425953941716377135?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/7425953941716377135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=7425953941716377135' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7425953941716377135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7425953941716377135'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/randome-thoughts-and-questions.html' title='Random Thoughts and Questions'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-3984964503310028039</id><published>2008-01-19T13:26:00.000-08:00</published><updated>2008-01-19T14:22:49.960-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rules'/><category scheme='http://www.blogger.com/atom/ns#' term='inheritance'/><category scheme='http://www.blogger.com/atom/ns#' term='object thinking'/><title type='text'>Rules vs. Overriding</title><content type='html'>In "Object Thinking" by David West, it appears that there are two main ways of making two different objects that respond to the same message react differently to those messages.&lt;br /&gt;&lt;br /&gt;The first is using polymorphism but that necessitates two different classes.  The other is making sure that the two objects will execute different rules when responding to the message.&lt;br /&gt;&lt;br /&gt;There is a third way that I'm not going to go over in this post; it's when two different objects have different state and react differently because of their differing state.&lt;br /&gt;&lt;br /&gt;The author discusses good and bad specialization on page 79.  I can't say that I am sure I know what the author is talking about.  If I take his words in their most literal sense, I get the following statements.&lt;br /&gt;&lt;br /&gt;1. Any time one class derives from another, it is assumed that the subclass is a specialization of the superclass.&lt;br /&gt;&lt;br /&gt;2. Specializing by extension means only adding methods but never overriding methods.  This is the good kind of specialization because it preserves the substitutability of subclasses for superclasses.&lt;br /&gt;&lt;br /&gt;3. Specializing by constraint (overriding a superclass' method) almost always results in a "bad" object because now you have to be concerned about how an object does something not just what it does.&lt;br /&gt;&lt;br /&gt;4. The exception in the footnote is that there will be some methods introduced high in the inheritance hierarchy that are designed to be overridden by subclasses and how the method does what it does is unimportant.&lt;br /&gt;&lt;br /&gt;Given that there are two ways of making two different objects react differently to a message, how do you pick between the two ways?  Is one way preferred in general?&lt;br /&gt;&lt;br /&gt;Let's say I'm doing some Object Discovery and definition of a Customer class.  From the domain experts I've found that there are two kinds of customers customers with discounts and customers without discounts.  Having a discount makes the payment calculation different but no additional behavior is added (for argument's sake).  If a Customer object can be given a discount or their discount can be revoked, then modifying the Customer's rules would be better than recreating the Customer as a CustomerWithDiscount or vice versa.  Perhaps the GoF's State Pattern would also be a good solution here.&lt;br /&gt;&lt;br /&gt;Let's say that I'm doing some Object Discovery and definition on some classes that represent various shapes in a drawing software package.  In this case it seems most fitting to use polymorphism for differing the way that the shapes draw themselves.  The reason it fits better sounds a lot like the exception listed in the author's foot note.&lt;br /&gt;&lt;br /&gt;Perhaps the reason that rules sound more natural for the Customer object is because it avoids us creating a subclass for every different kind of payment calculation (e.g. CustomerWithDiscountAndGoldMembershipAndOutstandingBalance).  In this case the rules approach is superior to even the State Pattern because you'd have to have a separate state class for each different method of payment.&lt;br /&gt;&lt;br /&gt;It looks like I need to read up on the author's thoughts on inheritance...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-3984964503310028039?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/3984964503310028039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=3984964503310028039' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3984964503310028039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3984964503310028039'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/rules-vs-overriding.html' title='Rules vs. Overriding'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-3972390986572022519</id><published>2008-01-18T21:32:00.000-08:00</published><updated>2008-01-18T23:18:21.289-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='description object'/><category scheme='http://www.blogger.com/atom/ns#' term='rule object'/><category scheme='http://www.blogger.com/atom/ns#' term='object thinking'/><title type='text'>Object Thinking and Description Objects</title><content type='html'>I'm reading about Description Objects in "Object Thinking" by David West, and I'm having a hard time wrapping my mind around them.  Their primary mentions are on pages 125 and 217.  The index in the book is a bit thin.  I've had to use O'Reilly's Safari book search feature to find things in the book.&lt;br /&gt;&lt;br /&gt;At their simplest, an Object Description is a map from labels (strings? atoms? symbols?) to primitives (e.g. string, int, etc.).&lt;br /&gt;&lt;br /&gt;Rather than fill up a CRC card with lots of attribute based responsibilities (e.g. know age, know first name, etc.), your object would have a responsibility called describe self.  This responsibility is met by returning a Description Object that contains attributes (e.g. age, first name, etc.).&lt;br /&gt;&lt;br /&gt;Description Objects create at least one benefit.  Let's say that you have a customer class that has the following attributes: age, first name, and last name.  Your domain analysis shows that some customers also have discount.  In a non-Object Thinking world, you would have two classes: Customer and CustomerWithDiscount.  The only need for the CustomerWithDiscount is the fact that it adds a single attribute.  In an Object Thinking world however, you would have a single Customer class but some Customers would return a Description Object that had a Discount label in it and others would not.&lt;br /&gt;&lt;br /&gt;This raises some questions:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;How does one Customer object get a Discount label in its Description Object?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;I see that we have two options:&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;The first is that if it's the Customer object that adds the Discount label that, taken to its somewhat logical conclusion, implies that a Customer object would have to know about all labels that a Customer could possibly have, when they should be added, and what values they should have.&lt;br /&gt;&lt;br /&gt;The other option is that some other object adds the Discount label, and that sounds like a breach of encapsulation to me.&lt;br /&gt;&lt;br /&gt;Of the two options, I dislike the first one the most (but the second option comes in close behind).  The first option implies that potentially a lot of intelligence would be placed in one class (what labels to add in different circumstances).  The second option might spread that intelligence all around the place.&lt;br /&gt;&lt;br /&gt;Perhaps we can use factory methods to encapsulate the population of the Description object.  For example:&lt;br /&gt;&lt;br /&gt;   Customer createCustomer(age, firstName, ...)&lt;br /&gt;   Customer createCustomerWithDiscount(age, firstName, ..., discount, ...)&lt;br /&gt;&lt;br /&gt;In this case the intelligence is all in one place and all of the encapsulation violations are done in one place.  Perhaps that's not too evil...&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;If the presence of a label in a Description Object or its value, influences the behavior of an object, how is difference of behavior implemented?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;If the Customer has a responsibility to calculate cost and a Customer with a Discount label in their Description Object calculates a different amount that a Customer without the Discount label, where does that decision logic go?&lt;br /&gt;&lt;br /&gt;You might say that this is a job for polymorphism but if that is the case, then we need two Customer objects: one with a discount and one without.  Hmmm, we introduced the Description Object to reduce the number of classes in the system but now we're back to two classes. &lt;br /&gt;&lt;br /&gt;So does this mean that if the presence of a label in a Description Object or its value can influence behavior of the object, that entry doesn't need to be in the Description Object (and probably should not be there)? &lt;br /&gt;&lt;br /&gt;I'll have to read up on Rule Objects but perhaps the cost calculation is a job for one or more rule objects (if inheritance and polymorphism are not appropriate).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What happens when you need to change a value in the Object Description&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;If the Object Description is implemented as a mutable map and another object just goes to the map and makes a change, this is a definite violation of encapsulation. &lt;br /&gt;&lt;br /&gt;The author states that Description Objects might have their own behaviors.  If the author considers setting values of entries in the Description Object as one of the  Description Object's behaviors, then we have created a new problem.  Now we need different kinds of Description Objects for different kinds of customers.  One Customer Description Object knows how to set the discount, while others know how to set other attributes. &lt;br /&gt;&lt;br /&gt;Perhaps rule objects would come to the rescue again.  When you create a Customer with a discount, you attach different rules to the Description Object than when you create other kinds of Customers.&lt;br /&gt;&lt;br /&gt;It seems that in Object Thinking rule objects might be used in many places where polymorphic methods would be used in non-Object Thinking.&lt;br /&gt;&lt;br /&gt;All this to say, I think I'll reexamine my CRC cards...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-3972390986572022519?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/3972390986572022519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=3972390986572022519' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3972390986572022519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3972390986572022519'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/object-thinking-and-description-objects.html' title='Object Thinking and Description Objects'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-4467541807118891020</id><published>2008-01-17T18:37:00.000-08:00</published><updated>2008-01-17T19:54:30.225-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='crc cards'/><category scheme='http://www.blogger.com/atom/ns#' term='bills'/><category scheme='http://www.blogger.com/atom/ns#' term='anthropomorphization'/><category scheme='http://www.blogger.com/atom/ns#' term='object thinking semantic net'/><title type='text'>Object Discovery on the BIll Payment System</title><content type='html'>I'm developing a bill payment system based on the principles of "Object Thinking" by David West.&lt;br /&gt;&lt;br /&gt;I drew up a semantic net based on the domain and covered almost an entire page.  I then started writing out CRC cards for the classes in the system and found that many of the classes I had drawn on the semantic net weren't classes at all.  Some became part of an object's description (payment schedule, payment rule, website, user name, password).  Several were outside of the system (e.g. website to pay bills on, check to mail the creditor).&lt;br /&gt;&lt;br /&gt;Since I'm practicing anthropomorphization, I listed each class' motivation on the CRC card.  For example a bill wants to pay itself.  A creditor wants to be paid the full amount on time.  A fund (that keeps track of how much money I have allocated for bill paying) wants to stay in the black.&lt;br /&gt;&lt;br /&gt;I was surprised by how my complex semantic net shrunk down to four objects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-4467541807118891020?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/4467541807118891020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=4467541807118891020' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/4467541807118891020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/4467541807118891020'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/object-discovery-on-bill-payment-system.html' title='Object Discovery on the BIll Payment System'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-7456744752572208384</id><published>2008-01-17T05:27:00.000-08:00</published><updated>2008-01-17T07:26:29.696-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='collaboration'/><category scheme='http://www.blogger.com/atom/ns#' term='object discovery'/><category scheme='http://www.blogger.com/atom/ns#' term='object thinking'/><category scheme='http://www.blogger.com/atom/ns#' term='contradiction'/><title type='text'>Object Thinking and Confusion over Collaboration</title><content type='html'>David West, the author of "Object Thinking", has a different definition of collaboration than I had ever seen.   &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The main difference (found on page 130) is noted in a scenario where object A is collaborating with object B.  He states that the object being collaborated with (B) is "not an object occupying one of object A's instance variables, a temporary variable declared in the method that object A is executing in order to satisfy the original request, or an object supplied to object A as an argument". &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then on page 254, the author states, "Collaborating objects are very tightly coupled.  For this reason, collaborations should occur inside the encapsulation barrier, with objects occupying the instance variables,  objects being received along with messages, and objects occupying temporary variables". &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At this point, I was confused, thinking I had found a contradiction.  Let's see if other references to collaboration clear things up...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On page 226, the author talks about the airplane collaborating with an instrumentCluster which on page 227 is shown as being held in an instance variable (Figure 8-2).  Okay, maybe that first definition just had a typo...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On the previous page, page 225, the author restates the definition of collaboration as found on page 130, the definition where collaborations don't take place between arguments, instance and temporary variables.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're keeping score, that's two references to collaborations taking place between arguments, temporary variables, and instance variables and two references for collaborations &lt;span class="Apple-style-span" style="FONT-STYLE: italic"&gt;not&lt;/span&gt; being between arguments, and the rest.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My thinking on the matter is that any time one object uses the services of another object, there is collaboration.  If collaboration is not occurring between instance variables, temporary variables, and arguments, then what is it called when you use the services of these other objects?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After some more thought, I think we have a catch-22 situation here.  When you are filling out a CRC card, and you are about to write down a collaborator, you must first think whether or not that collaborator will be stored in an instance variable, temporary variable, or argument.  If the collaborator will be referenced via an instance variable, then it's not a collaborator at all and you should not write it down.  That sounds like jumping to implementation details during the "Object Discovery" process.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If collaboration is something that is to be discovered during the "Object Discovery" process, then you cannot make restrictions on what is and what isn't a collaboration based on implementation details.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-7456744752572208384?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/7456744752572208384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=7456744752572208384' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7456744752572208384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/7456744752572208384'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/object-thinking-and-confusion-over.html' title='Object Thinking and Confusion over Collaboration'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-3091992765526113115</id><published>2008-01-03T22:06:00.000-08:00</published><updated>2008-01-17T07:27:46.637-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bills'/><category scheme='http://www.blogger.com/atom/ns#' term='object thinking'/><title type='text'>The Secret (and Guilt-Ridden) Life of Bills</title><content type='html'>I'd like to write a bill paying system for Mac OS X in Objective-C. I'm looking at the system from an "Object Thinking" (by David West) perspective.&lt;br /&gt;&lt;br /&gt;So if beer can want to hop on a truck to be taken to a customer, a bill (the kind you pay) can want to be paid, right?&lt;br /&gt;&lt;br /&gt;In fact, as I see it, a bill knows that it is a debt to society (or at least to me). It feels terrible about its mere existence. All it wants is to secure funds so that it can pay itself, record the fact that it paid its debt, and then shuffle off the mortal coil.&lt;br /&gt;&lt;br /&gt;I almost start feeling bad for the little bill.&lt;br /&gt;&lt;br /&gt;I don't think I'd use the words guilt or despondent anywhere in the code, but it's a fun way of looking at the bill.&lt;br /&gt;&lt;br /&gt;Before reading "Object Thinking" the sad little bill would have been an inanimate, vegetable of a bill, with no motivation or smarts (or guilt).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-3091992765526113115?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/3091992765526113115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=3091992765526113115' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3091992765526113115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/3091992765526113115'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/secret-and-guilt-ridden-life-of-bills.html' title='The Secret (and Guilt-Ridden) Life of Bills'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-5748374016339768249</id><published>2008-01-03T21:44:00.000-08:00</published><updated>2008-01-17T07:27:32.026-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='beer'/><category scheme='http://www.blogger.com/atom/ns#' term='object thinking'/><title type='text'>Beer and Motivation</title><content type='html'>This post is not about my drinking habits. It's about a couple of paragraph's from "Object Thinking" by David West. Since "beer" does not appear in the index, the paragraphs are on page 298.&lt;br /&gt;&lt;br /&gt;The author states that the beer is trying to get into a bottle, get capped, and into a truck. One obvious (and wrong) way of implementing this would be to make the beer a controlling object ("Vat, pour me into a bottle", "Capper, cap me", etc.). This approach is wrong because the control becomes too centralized.&lt;br /&gt;&lt;br /&gt;So how would you implement this? Could you use events?&lt;br /&gt;&lt;br /&gt;For example, the beer registers with the vat so that the beer is told when a vat full of fresh beer is ready. The bottle registers with the beer so that the bottle can be told when the beer is ready to be poured into the bottle. I'm not sure I like this approach. If I look at these objects as humans, as the author encourages, I see behavior that I don't like to see in humans. It's that whole, "I'm ready (and tapping my foot while I'm waiting for you to meet my expectations)." If you link enough of these kind of events together, I'm concerned that you'll have a lot of weak links and hard to follow logic.&lt;br /&gt;&lt;br /&gt;That is why I want to implement some simple system based on the principles found in "Object Thinking"; to see if my concerns are valid.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In a &lt;a href="http://polymorphicpodcast.com/shows/objectthinking/"&gt;podcast (part two of two)&lt;/a&gt; the author talks more about the beer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-5748374016339768249?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/5748374016339768249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=5748374016339768249' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/5748374016339768249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/5748374016339768249'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/beer-and-motivation.html' title='Beer and Motivation'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7956719137458583385.post-2899463523511206082</id><published>2008-01-03T21:15:00.000-08:00</published><updated>2008-01-03T22:18:17.854-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='object thinking'/><title type='text'>Thinking about "Object Thinking"</title><content type='html'>A few weeks ago a new acquaintance recommended that I read David West's "Object Thinking" book.  Now I had thumbed through the book before and had dismissed the book largely because of its strong focus on philosophy and history.  I'm a "show me the code" kind of guy after all.  I was reluctant to take his advice.&lt;br /&gt;&lt;br /&gt;But here was this smart, pragmatic, in-the-trenches guy basically telling me that he wanted to work with people who agreed with this book.  The thought of using a book on philosophy and history as a litmus test for knowing if you wanted to work with someone made a strong impression on me so I bought the book, and read through it quickly.&lt;br /&gt;&lt;br /&gt;I found the author's perspective on OO interesting and unorthodox.  I got to the end of the book and had a lot of questions.  I decided to read the book again focusing on deeper comprehension and I'm very glad I did.&lt;br /&gt;&lt;br /&gt;The strange thing is that the second reading answered very few of my questions.  It did make a lot of things more clear but I still had questions.  My questions fall into the following categories:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Does "Object Thinking" work in the real world?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;How would you implement "Object Thinking"?  To really understand something, I like seeing it from its inception to its completion.  For programming topics that means from concept to code (with apologies to Jesse Liberty).  This book covered the concepts very well (all that philosophy, history, and culture stuff) but strayed away from code.&lt;/li&gt;&lt;li&gt;Can I just pick and choose some of the authors principles and still reap the benefits?  Or do I have to adopt the principles that make me uncomfortable?&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Having questions after reading a book is not necessarily a bad thing.  In fact that 's why I'm finally blogging after who knows how many years of putting it off.&lt;br /&gt;&lt;br /&gt;My goal is to try to approach one or more simple projects using the "Object Thinking" book as my guide.  I'd like to document that process on this blog.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7956719137458583385-2899463523511206082?l=timjstewart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://timjstewart.blogspot.com/feeds/2899463523511206082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7956719137458583385&amp;postID=2899463523511206082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2899463523511206082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7956719137458583385/posts/default/2899463523511206082'/><link rel='alternate' type='text/html' href='http://timjstewart.blogspot.com/2008/01/thinking-about-object-thinking.html' title='Thinking about &quot;Object Thinking&quot;'/><author><name>Tim Stewart</name><uri>http://www.blogger.com/profile/09462164199588340287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_I8udcGGmplM/R36BV_9YkZI/AAAAAAAAAAM/kw36BlBhCqQ/S220/me.jpg'/></author><thr:total>0</thr:total></entry></feed>
