Microsoft stylecop

StyleCop has quickly become one of the my favorite tools.  It is just like FxCop but for source code instead of compiled assemblies.  StyleCop has helped me to write much better code without a lot of overhead.   As a side effect during code reviews I am able to spend more time on business logic and a lot less on code style.

You can run StyleCop on a whole solution, project, or single file.  As well you can configure which rules to use per project and they are stored in the Settings.StyleCop file within your project directory.  There are a few rules that I always turn off since I personally don’t find them to be value added: SA1027: TabsMustNotBeUsed, SA1101: PrefixLocalCallsWithThis, SA1200: UsingDirectivesMustBePlacedWithinNamespace.  I also exclude auto-generated and designer files from analysis.  No sense in analyzing files that I have no control over.

One minor annoyance that I do have with the configurations is that when trying to figure out how to fix violations the detailed settings box is always blank.  The detailed information is well documented though in the StyleCop.chm located in {Program Files}\Microsoft StyleCop 4.3\Docs.

After you play with StyleCop for a short while you will wish for a more automated solution to fix the violations and more real time syntax checking.  Luckily there is a solution for this if you are using Resharper, the StyleCopForResharper (SCR#) plugin available on codeplex.  SCR# is an open source project that includes real-time syntax checking as well as quickfixes and code cleanup options.  I have been using this plugin for a couple of months now without any issues.  The recently just released an RC candidate. 

If you want to have StyleCop run as part of the build there are a couple of solutions.  StyleCop includes MSBuild integration for running with each build in Visual Studio.  If you want to run it from the command line or nant scripts, there is an add-on available at http://stylecopcmd.wiki.sourceforge.net/ .  If you want to run it as part of a TFS Team Build there is an MSBuild extension available at codeplex.com/MSBuildExtensionPack and a good blog post on implementation at http://blogs.blackmarble.co.uk/blogs/rfennell/archive/2008/10/15/using-stylecop-in-tfs-team-build.aspx

Enabling the MSBuild integration is super simple.  You just need to import the StyleCop target.

<Import Project="$(ProgramFiles)\MSBuild\Microsoft\StyleCop\v4.3\Microsoft.StyleCop.targets" />

 

There is also an option to treat the StyleCop violations as errors instead of warning by adding the following to the global property group for the project file .

<StyleCopTreatErrorsAsWarnings>false</StyleCopTreatErrorsAsWarnings>

 

Lastly, there is an SDK to allow you to write you own custom rules.  Writing rules look to be pretty easy.  I have include a sample custom rules project below.  There are two rules within the project: 1.) Fail on every file.  Not a useful rule but just a sample to show how to through a violation.  2.) checks that all fields start with an underscore followed by a lowercase letter.  To install the custom rules, you just need to copy them to the StyleCop install folder and possibly the MSBuild StyleCop folder.  The one thing that I did notice is that one you launch a new instance of Visual Studio with your custom rules installed, you have to close all instance of the Visual Studio in order to deploy a new version of your custom rules.

Microsoft StyleCop.pptx (96.43 kb)

SEVDNUG StyleCop CustomRules Feb2009.zip (76.70 kb)

SEVDNUG StyleCop Feb2009 Demo.zip (25.08 kb)


Parsing HTML and Stripping HTML Comments

Two good post by Phil Haack

http://haacked.com/archive/2008/11/10/the-landmine-of-parsing-html-and-stripping-html-comments.aspx

http://haacked.com/archive/2008/11/11/html-stripping-challenge.aspx


VS2008 SP1 Hotfix to Support -vsdoc.js IntelliSense Doc Files

Here is a hotfix to accompany Microsoft's new new jQuery VSDoc file

http://code.msdn.microsoft.com/KB958502/Release/ProjectReleases.aspx?ReleaseId=1736

The hotfix requires vs2008 sp1 to work.


Flash Player Caching Problem

I have been having issues with data in a Flex application not refreshing when configuration changes are made.  I thought that the issue was related to IE caching since it works as expected if the check for newer versions of stored pages to Every time I visit the webpage.  However, even when I put the meta http-equiv Expires tag to 0, it didn't fix the problem.  It turns out that it is the Flash player that is caching the data.  I found a fix at http://www.communitymx.com/content/article.cfm?cid=827EA

var gateway:HTTPService = new HTTPService();
gateway.url = urlValue + "?cachebuster=" + new Date().getTime();

Auto-generating help with NAnt and CC.net

I have been thinking about generating the help documentation during my cc.net builds and the article below looks to be exactly what I need. 

 

Original Post at Auto-generating help with NAnt and CC.net 

Sancastle Help File Builder tool is a fantastic GUI interface to configure and create both HTML Help and web page documentation (I wont' discuss this in depth here). Basically just point it at your .exe or .dll set a few parameters and you are off. Great when you are manually doing it, but for automation; no. Well inside the deployment directory is a command line tool; SandcastleBuilderConsole.exe. Use the GUI tool to create your project and set any parameters and then save it as an .shfb file. Then pass your .shfb file generated to the SandcastleBuilderConsole application and your help file will be created.

Now both the Sandcastle Help File Builder tool and its command line version need the XML comments from your application. Visual Studio will generate this automatically by going to the project properties build tab and selecting the XML documentation file tick box. If however you are wanting NAnt to do it automatically each time you perform a build, add the doc attribute to your csc element like this:-

   1: <csc target="library" output="nant_build\ReportsPdf.dll" 
   2:          doc="nant_build\ReportsPdf.xml">

Then somewhere within your target element, add the command to run the exe which points to your SandCastleBuilderConsole.exe, like this:-

   1: <exec 
   2:       program="C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe"
   3:       commandline="&quot;${SandCastleDocPath}\${SandCastleHFBProject}&quot;"
   4:       failonerror="true"/>

The two properties for the commandline attribute are set earlier on in the NAnt file like so:-

   1: <property name="SandCastleHFBProject" value="sandcastle.shfb"></property>
   2: <property name="SandCastleDocPath" value=".\Sandcastle\"></property>

Automated Database Deployments

I am using the VSTS Database Editon to manage my schema in development as well.  For deployments I am using a combination of VSTS Database Edition generate scripts, manually created data migration scripts and nant. 

Steps for generating scripts for deployment:

  • Create a new database with the schema from the last production release.
  • Do a Schema Compare in VSTS DB Edition with the project as the source and the new database as the target.  Export to the Editor so that you can get the sql script to run but don’t execute the script yet.  This will create you the upgrade script.
  • Do a Schema Compare in VSTS DB Edition with the new database as the source and project as the target.  Export to the Editor so that you can get the sql script to run but don’t execute the script yet.  This will create you the back out script.
  • Scan thru the generate scripts and make any additions/changes to handle the data migration.  Unfortunately it is hard to auto generate a script to manage the data side of the upgrade.
  • To test the scripts, restore a copy of the production database and run the upgrade/back out scripts against it.

Nant Script used for Upgrade Deployment:

    <!—List of upgrade scripts -->
   <property name="releases" value="3.0.1,3.0.2,3.0.3,3.0.4,3.0.5,3.0.6,3.0.7" /> 

   <!—Reverse list of upgrade scripts used for back out -->
   <property name="releases.reverse" value="3.0.7,3.0.6,3.0.5,3.0.4,3.0.3,3.0.2,3.0.1" /> 

   <!—Current production release.  Could get from DB.  Used to determine how many back out scripts to run -->
   <property name="current.version" value="3.0.7" /> 

   <!— Release package number.  Used to determine when to start running the upgrade scripts.
   <property name="current.release" value="3.0.8" /> 

 

<!—Loop thru the releases, run all once you either hit the current release or what is in prod original.  -->
<!-- Files are name v.X.X.X.AlterScript.sql and vX.X.X.DataAlterScript.sql -->
<property name="runmorepappscripts" value="false" />
<foreach item="String" in="${releases}" delim="," property="count">
    <if test="${property::get-value('count') == property::get-value(current.release')}">
                    <property name="runmorepappscripts" value="true" />
    </if>
    <if test="${property::get-value('runmorepappscripts') == 'true'}"> 
          <property name="filename" value="${path::combine(release.database.dir, 'v' + count + '.AlterScript.sql')}" />
          <if test="${file::exists(path::combine(release.database.dir, filename))}">
                    <echo message="Running ${filename} script against ${database.name} database  on ${database.server}" />
                    <sql 
                        connstring=""
                        transaction="true"
                        delimiter="GO"
                        delimstyle="Line"
                        batch="false" 
                        print="true" 
                        source="${path::combine(release.database.dir, filename)}"
                        verbose="${verbose}" />
                    <echo message="Completed ${filename} script against ${database.name} database  on ${database.server}" />
          </if>
          <property name="filename" value="${path::combine(release.database.dir, 'v' + count + '.DataAlterScript.sql')}" />
          <if test="${file::exists(path::combine(release.database.dir, filename))}">
                    <echo message="Running ${filename} script against ${database.name} database  on ${database.server}" />
                    <sql
                                    connstring="" 
                                    transaction="true"
                                    delimiter="GO" 
                                    delimstyle="Line" 
                                    batch="false" 
                                    print="true" 
                                    source="${path::combine(release.database.dir, filename)}" verbose="${verbose}" />
                    <echo message="Completed ${filename} script against ${database.name} database  on ${database.server}" />
          </if>
    </if>
    <if test="${property::get-value('count') == property::get-value(current.version')}">
                    <property name="runmorepappscripts" value="true" />
    </if> 
</foreach> 
 
Nant Script for backout
 
<!—Loop thru the releases reverse, run all until you hit what was original in prod.  Files are name v.X.X.X.AlterScript.sql and vX.X.X.DataAlterScript.sql --> 

<property name="runmorepappscripts" value="true" /> 

<foreach item="String" in="${releases.reverse}" delim="," property="count">
                <if test="${property::get-value('count') == property::get-value(‘current.version')}">
                                <property name="runmorepappscripts" value="false" />
                </if>
                <if test="${property::get-value('runmorepappscripts') == 'true'}"> 

                                <property name="filename" value="${path::combine(release.database.dir, 'v' + count + '.BackoutAlterScript.sql')}" />
                                <if test="${file::exists(path::combine(release.database.dir, filename))}">
                                                <echo message="Running ${filename} script against ${database.name} database  on ${database.server}" />
                                                <sql connstring="" transaction="false" delimiter="GO" delimstyle="Line" batch="false" print="true" source="${path::combine(release.database.dir, filename)}" verbose="${verbose}" />
                                                <echo message="Completed ${filename} script against ${fuzion.database.name} database  on ${fuzion.database.server}" />
                                </if>
                                <property name="filename" value="${path::combine(release.database.dir, 'v' + count + '.BackoutDataAlterScript.sql')}" />
                                <if test="${file::exists(path::combine(release.database.dir, filename))}">
                                                <echo message="Running ${filename} script against ${database.name} database  on ${database.server}" />
                                                <sql connstring="" transaction="false" delimiter="GO" delimstyle="Line" batch="false" print="true" source="${path::combine(release.database.dir, filename)}" verbose="${verbose}" />
                                                <echo message="Completed ${filename} script against ${database.name} database  on ${database.server}" />
                                </if>
                </if>
</foreach>

Lack of complaints does not equal success : How To Be A Good Product Manager: Product management tips

Great post on lack of complaints not equaling success.  I have seen lots of developers think this way only to be proven wrong later when they are struggling with user adoption.

Taken from: Lack of complaints does not equal success : How To Be A Good Product Manager: Product management tips

If you want to be a bad product manager, assume that lack of complaints means your product is successful. There are lots of customers using your product, so when you add a new feature or make a change and don’t hear complaints, that must mean that everything is working fine. If something was really unusable or broken or didn’t meet your customers’ needs, they would let you know. It’s much easier to just make a change or add something to the product and wait to hear feedback than to do a whole bunch of research and testing first — that’s just a waste of time, right?

If you want to be a good product manager, proactively seek out feedback rather than wait for complaints. Lack of complaints does not mean that you have a fantastic product — it just means that you are not getting any complaints.

Waiting for customers to complain is problematic for several reasons:

  1. Not all customers complain. Think about all of the products you use on a daily basis, and the problems you encounter with all of them. There may be a confusing button on your cell phone, a strange error message on your online banking site, or a slippery grip on a kitchen gadget. How many times have you taken it upon yourself to contact the organization responsible for that product? Despite the multitude of different ways to complain — from the traditional methods like contacting the company directly, to more modern methods of voicing your frustration on Twitter or a product review site — most customers do not make the effort to send this feedback directly or indirectly to the company. A product manager simply hoping to hear from customers with problems is only going to hear about a fraction of the problems from only a fraction of the customers. For every customer who vocally complains, there are likely tens or hundreds or thousands of others who are silent.
  2. Lack of complaints may mean lack of customers or users. While we would like to think that lack of feedback means lack of problems, it is often that lack of feedback means lack of experience on which to provide feedback. When a product manager adds a new feature to a product and does not hear any complaints about the feature, he may assume that the feature is a success and the fact that customer service has not received any complaints is because it is working smoothly. Unfortunately, it could be just as likely that no one is using the new feature, and thus no one has any experience about which to complain. If there are a small number of customers using the new feature, relying on their complaints alone may provide very skewed feedback.
  3. By the time someone complains, it is usually too late. While the previous two points are worth noting, this is truly the most important reason to not simply wait for complaints. For physical products, changes to a product after it is in the market can be extremely expensive and time consuming to rectify. From a purely financial standpoint, it is the responsibility of a product manager to attempt to produce the best product and thus avoid costly changes. However, even for web-based products which can be changed very quickly and cheaply, waiting for customers to complain is backwards approach to product development. Sure, it may be gratifying on the surface to say that you are able to respond quickly to problems that customers raise, but wouldn’t it be better to prevent these problems in the first place? Would you rather buy a car from a company who listens to your complaints and reacts when your car has problems, or would you rather buy a car from a company who produces a car which will not cause you problems and will not cause you to have to complain?

Ultimately, no matter how hard an organization tries to address problems and meet needs, people will complain, and product managers can benefit from listening to and understanding those complaints. However, when a legitimate complaint is lodged, rather than just reacting to it, product managers should ask, “How did we not know about this earlier?” Is the complaint related to something that the team should have known about? Would a better understanding of the customer needs have helped prevent it? Would better design or more usability testing have uncovered the underlying problem? Did a defect make its way into the final product? Did we know about the problem and just hope that no one would notice? How did it come to this — that a customer had to complain in order for us to realize something was not right?

Complaints are a valuable source of information which can be used to help improve your product, though they are only one source and should be used carefully. Product managers need to be proactive at gathering feedback from customers and prospects, though activities like usability testing, Win/Loss analysis, site visits, observational interviews, and other types of qualitative and quantitative research. Rather than just waiting for complaints and responding to them, product managers need to be focused on preventing them from occurring and getting to the root cause when they do appear.

Jeremy's Other Laws of Continuous Integration

Good laws of continuous integration from Jeremy Miller.  The first law is pretty funny but oh so true.

Taken from: Jeremy's Other Laws of Continuous Integration

1.) If you check in very often and/or first, you can make merge conflicts be someone else's problem

2.) Check in as often as you come to a stopping point.  The more frequently you check in, the less troubling your merge conflicts will be.  For the most part, I think you can make merge conflicts almost entirely go away after the first couple weeks of the project.  We had a mild conflict today (that spawned my tongue in cheek remark about checking in first) that was caused by one pair renaming a testing utility method to make it more consistent with our other testing methods, while my pair was still using the existing method name.  Both pairs knew it was coming so it was no harm, no foul

3.) Communicate with your team members anytime you think you might be doing something that would cause a merge conflict.  Yet one more reason why a colocated team beats a distributed team

4.) Find ways to divide your work into smaller chunks.  If you can't check in new code for days at a time because you aren't at a clean point, you may have some serious problems with your design.

5.) If you can't check in your code for a long time ( > 1/2 a day let's say), be sure to update your version of the source code with the updates from the rest of the team to make your eventual checkin easier

6.) Rotate your build notification sounds.

7.) And in the "do as I say not as I do" category, you might learn how to use a merging tool (then come teach me).


GridView doing double postback when using ImageButton for Delete

I just spent a bit of time trying to figure out why my GridView was randomly doing a double postback when deleting rows.  When I hooked up the debugger and put a break point on in the Page_Load, I would see that it was being called twice.  It turns out that there is a bug with the GridView that causes this behavior.  If you use either a LinkButton or regular Button, the GridView works as expected.  There is also a workaround @ http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=105123


ActiveRecord Codesmith Template Updated

I have made a bunch of changes to the ActiveRecord template.  Below is the list of all of the changes. 

Codesmith.zip (18.14 kb)

Changes:

Lookup table Enum and SQL Generation

I have always used enumerations for all of my lookup tables so that I don't have to hard code the lookup ID value in code.  Until now I had generated these by hand but I finally got around to creating the ability to generate the enum and the sql insert statement.  The template expects an integer primary key and a single string based column.  You can have other values in the table but the template will ignore them. 

The SQL script can either be generated with each table in it's own or as a single file.  The template checks to see if the primary key is an identity column and adds the identity_insert tag.  As well the generate script checks to see if the lookup value based on it's primary key is already in the table before trying to add it.  This allows you to run the script multiple times wthout any issues.

Views as ActiveRecord Classes

I added the ability to specify views to be used to generate ActiveRecord classes.  In order to properly generate the class you have to add an extended property to the view called PrimaryKey and specify the column that is the primary key. 

Self-Referencing Tables

I changed the code to look for self-referencing tables and append List to the end of the property.

Ability to not generate Tests

Added a flag to turn off the test code generation.  All the test classes are is a placeholder anyway which so folks didn't want.

Output Structure

I changed the output structure to better organize the code based on the type of database entity (enum, table, view, sql, etc)

PropertyNames structure for use with nHibernate Expression classes

One thing that I have always disliked about using the nHibernate expression classes was that the properties are string values and cannot be compile time checked.  This unfortuantely leads to only finding errors at runtime for the expression queries.  To solve this problem, I implement the suggestions from the Summer of Nhibernate Screencast (http://www.summerofnhibernate.com ) to create a static class for each ActiveRecord class with the name of each property as a string.  I also add a string value for all of the BelongsTo relationships to get return the RelationshipName.ID since you need that in many instances.  As well I created an ActiveRecordTableNames.cs file that has a listing of all of the tables names.