Friday, May 30, 2008
StyleCop
Earlier in the week, thanks to
The Morning Brew #101 I downloaded and installed
Microsoft Source Analysis for C# (aka StyleCop).
As a fan of
FxCop I was interested to find out what this had to offer and so ran it on some new code that Bruce and I have been working on for a
Madgex ILP project
Running StyleCopI ran it against one (already FxCop'd) file, and came up with the following deviations from the rules (displayed in a new "Source analysis" window):
SA1101: The call to m_source must begin with the 'this.' prefix to indicate that the item is a member of the class.
SA1200: All using directives must be placed inside of the namespace
SA1308: Variable names must not start with 'm_'
SA1502: The constructor must not be place on a single line. The opening and closing curly brackets must each be placed on their own line.
SA1600: The class must have a documentation header.
SA1600: The constructor must have a documentation header.
SA1600: The field must have a documentation header.
SA1600: The property must have a documentation header.
SA1633: The file has no header, the header Xml is invalid, or the header is not located at the top of the file.SA1101 and SA1308 go hand in hand to my mind. We use m_ to indicate that the item is a class level field, and is the underlying element for a property. Using "this." instead also shows that this is what is happening. So, I don't have a problem with this at all.
SA1200 is a weird one, this differs from the templates and almost all sample code I've seen on MSDN etc. There have been quite a few blog posts about this.
SA1502 is only ususally done within our code when inheriting the constructor from the base class or this class, i.e. either
public NewClass(string name)
: base(name) {}or
public NewClass(string name, string description)
{
this.myName = name;
this.myDescription = description;
}
public NewClass(string name)
: this(name, null) {}Changing
{} to be
{
} makes little difference and may improve readability.
All the variations of SA1600 are fine - documentation is useful, and using the summary sections is as good a way as any. I did get some subsequent warnings when I only used a one word description
SA1630: The documentation text within the summary tag does not contain any white space between words, indicating that it most likely does not follow a proper grammatical structure required for documentation text.or a very short description
SA1632: The documentation text within the summary tag must be at least 10 characters in length. Documentation failing to meet this guidelines most likely does not follow a proper grammatical structure required for documentation text.SA1633 is tricky, there is some
documentation explaining the rules that a file header must adhere to, which indicates that the minimum file header must be:
//<copyright file="Widget.cs" company="Sprocket Enterprises">
// Copyright (c) Sprocket Enterprises. All rights reserved.
// </copyright>This is probably the rule I dislike the most. I don't have a problem with file headers, but I don't think that the style of those headers should be enforced. Also, not all code actually is done via a Company - it could be personal code, in which case author would be more appropriate.
Changing the settings
There is a settings editor which is included in the Program Files folder, which can be started from the command line as:
C:\Program Files\Microsoft Source Analysis Tool for C#>SourceAnalysisSettingsEditor Settings.SourceAnalysiswhere Settings.SourceAnalysis is the predefined file created/installed as part of the installation process.
This editor allows settings to be altered/changed to provide additional or more appropriate checks. Rules can be switched off - so I can prevent SA1633 from being reported to me. Company information and copyright text can be added so that the Header checking verifies against known and predefined information.
The settings editor can also be accessed from with the Visual Studio IDE by right-clicking on the project and selecting the menu option "Source Analysis Settings". This then created project level settings which is useful when wanting to change the settings on a project by project basis. To my mind, I'd rather set it on a machine level, and use the same settings across all of my projects - my use of a tool like this would be to ensure consistent styling, and changing the settings on a per project level stops this. There is an element of merging that can be acheived, by selecting the "Settings File" tab in the editor but how this works in practice I haven't, as yet, had chance to investigate.
The .Net Afficionado has some useful links to find out more information and
Love The Dot has an article about
creating custom rules.
Labels: ilp, Style code analysis
// posted by Jane @ 1:35 PM
Comments:
Monday, April 28, 2008
More on transactions
After Friday's
experiment with transactions in SQL Server I got to wondering about what would happen to actions between the
ROLLBACK TRANand the
IF @@TRANCOUNT > 0
COMMIT TRANso I amended the code to have an additional INSERT as follows (Note: I also changed the final
COMMIT TRAN to be a
ROLLBACK TRAN to help show the differenence)
BEGIN TRAN
INSERT INTO COUNT VALUES (1)
BEGIN TRAN
INSERT INTO COUNT VALUES (4)
ROLLBACK TRAN
INSERT INTO COUNT VALUES (99) -- New line
IF @@TRANCOUNT > 0
ROLLBACK TRANwhich results in the value 99 being inserted into the table, outside of the scope of any transactions - all transactions were rolled back in the inner
ROLLBACK TRANTo ensure that the second part of the statement, which might be unrelated to the first and therefore not dependent on the result of that transaction, is within a transaction, the following seems to work with the expected results:
BEGIN TRAN
INSERT INTO COUNT VALUES (1)
BEGIN TRAN
INSERT INTO COUNT VALUES (4)
ROLLBACK TRAN
IF @@TRANCOUNT = 0
BEGIN TRAN
INSERT INTO COUNT VALUES (99)
IF @@TRANCOUNT > 0
ROLLBACK TRANNo new row is added as a result of this action as now all actions are covered within a transaction.
Labels: ilp, SQL
// posted by Jane @ 1:03 PM
Comments:
Friday, April 25, 2008
TSQL Transactions - simple nesting
After
Bruce and I were looking at
DBVerse earlier, we started specifiying how our tool would work, especially with regards to transaction. Our outer process will need to handle its own transactions, and will need to be aware of inner errors and inner transactions to ensure that errors don't ensue.
For example, in the following scenario
BEGIN TRAN
INSERT INTO COUNT VALUES (1)
BEGIN TRAN
INSERT INTO COUNT VALUES (4)
ROLLBACK TRAN
COMMIT TRANthe following error is produced
Msg 3902, Level 16, State 1, Line 17
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.This is because the inner
ROLLBACK TRAN rollsback ALL transactions, not just the inner transaction. So, by the time the
COMMIT TRAN is called there are no longer any transactions.
To get around this, the code can be changed to be:
BEGIN TRAN
INSERT INTO COUNT VALUES (1)
BEGIN TRAN
INSERT INTO COUNT VALUES (4)
ROLLBACK TRAN
IF @@TRANCOUNT > 0
COMMIT TRANwhich works happily and will not cause an error.
NOTE: Count is just a test table I created with a single column of Count which is defined as an int. Nothing very exciting.
Labels: ilp, SQL
// posted by Jane @ 6:01 PM
Comments:
Database change management: DBVerse review
A few weeks ago I found a reference to
DBVerse in
The Morning Brew #58 which seemed like a great starting point for a problem I've had time and time again - keeping databases in sync from a structure perspective making sure that all the dependencies are in place and there is little or no risk when running these changes into a live server.
Bruce and I spent an hour or so today looking into this tool as part of our
Madgex ILP time, and the following are our observations.
DBVerse is a C# project, which you install as a template on your machine. In my case, I copied the entire
DbVerseDatabaseProjectTemplate.zip file, still as a zip, into my My Documents\Visual Studio 2005\Templates\ProjectTemplates folder.
To add a new DBVerse project to a solution, it is pretty simple, just a case of Adding a new project of type DbVerse Database Project. This will then create a new project, consisting of a DbVerse folder (which keeps all the required DLL and EXE files), a Scripts folder (in which any SQL scripts can be kept) and three cs files - Methods.cs, Methods.Initialize.cs and Methods.Updates.cs
The cs file we were most interested in was Methods.Updates.cs as that is our prime requirement - record and manage updates. In DBVerse updates can be scripted as SQL and put into the Scripts folder and then executed via
Db.ExecuteScript("UpdateJaneTestTable.sql"); or by using the DB objects that are exposed from the
Lunaverse.DbVerse.Core such as
Db.AddTable("JaneTest");
Db.Table("JaneTest").AddColumn("ID", DataType.Int);
Db.Table("JaneTest").AddColumn("Name", DataType.NVarChar(255));. I'm a big believer in scripting out changes in SQL, as these can be tested against the database and written in a none destructive manner (i.e. checking for existance of an object before updating it etc).
Each update method is given an attribute similar to
[Update(2, "Jane Dallaway", "25/04/2008")] where 2 is the update number, "Jane Dallaway" is the author and "25/04/2008" is the date that the update was written.
The DBVerse project produces a dll, which is run via either a GUI or a console application. To run the updates via the console application I ran
Lunaverse.DbVerse.Console.exe ApplyAllUpdatesA new table is created - Database Updates - which records all the updates scripts which have run, storing the ID, Method Name, Author, Authored data and Application Date.
On subsequent runs I expected this table to be checked before any updates were applied, and to test this I created the following Update
[Update(3, "Jane Dallaway", "25/04/2008")]
public void InsertData()
{
Db.ExecuteScript(("InsertData.sql"));
}I commented out all previous Updates to make it easy to check and ran
Lunaverse.DbVerse.Console.exe ApplyAllUpdatesThe output was
Starting...
------------------------------------------------------------
Server=localhost Database=JaneTest Method count=-1
------------------------------------------------------------
Method starting [ApplyAllUpdates]
------------------------------------------------------------
Script [InsertData.sql] was run
Inserted row into table [DatabaseUpdates] ('InsertData', 'Jane Dallaway', '25/04/2008 00:00:00', '25/04/2008')
------------------------------------------------------------
Method finished [ApplyAllUpdates]
------------------------------------------------------------
Done: all methods completed
------------------------------------------------------------When I checked the database I got the following output:
ID Name Description
1 Test Test via DBVerse
(1 row(s) affected)so all as I expected.
I then ran the console application again, and got the following output
Starting...
------------------------------------------------------------
Server=localhost Database=NewDesignPartners Method count=-1
------------------------------------------------------------
Method starting [ApplyAllUpdates]
------------------------------------------------------------
Script [InsertData.sql] was run
------------------------------------------------------------
Method finished [ApplyAllUpdates]
------------------------------------------------------------
Done: all methods completed
------------------------------------------------------------which has differing output to the previous time in the Script [InsertData.sql] line as last time we were notified what was inserted and this time we weren't.
On examining the database, the insert was run again resulting in the following rows
ID Name Description
1 Test Test via DBVerse
1 Test Test via DBVerse
(2 row(s) affected)This indicates that the check that the update hasn't already been run is causing an issue and cannot be relied upon. This invalidates the tool for our use. All of our other observations were minor - such as not being able to work out how to run all the updates in one go in the GUI, I could only seem to work out how to run one update at a time.
This project is a work in progress, and is probably worth keeping an eye on. Maybe I'll revisit it at a later stage, but I think it might be time to write something that does exactly what we need for the
Madgex environment.
Labels: database change management, ilp, SQLServer
// posted by Jane @ 1:09 PM
Comments:
Wednesday, April 09, 2008
TSQLUnit Updates - Helper Functions
Last week I attended another
ILP workshop, this time about
nUnit. This made me remember about the
TSQLUnit testing framework, and the changes I had made to it whilst using it at my previous company and the fact that these changes were just sitting in a file somewhere and had never been shared.
The project which benefited from the most from TSQLUnit was one working with a large set of complicated calculations. Due to the nature of the data, this work was carried out in the database layer. These calculations were based on a well specified system, and so was a great candidate for thorough unit testing. Whilst building the calculation engine, I enhanced the base TSQLUnit installation to have some additional helper functions to save me coding the same thing over and over again.
I added a set of value checking helper procedures as follows
tsu_CheckValues_Decimal, tsu_CheckValues_Int, tsu_CheckValues_String, tsu_CheckValues_Date, tsu_CheckValues_Money all of which take 3 parameters - the first the expected data value, the second the actual data value, and the third an optional parameter expressing the message to be displayed to the developer if this assertion fails.
For example,
EXEC tsu_CheckValues_Int 0,1,'Oops'
results in the following error being recorded 'Integer value mismatch Oops - Unexpected Result. Expected: 0. Actual: 1'
In additon I added some helper functions to assist in the generation of error messages as follows
tsu_GenerateErrorMessage_Date, tsu_GenerateErrorMessage_Int, tsu_GenerateErrorMessage_Real, tsu_GenerateErrorMessage_String all of which take 3 parameters, the first being the initial part of the message to display, the second the expected data value and the final the actual data value.
For example,
SELECT dbo.tsu_GenerateErrorMessage_Int('Integer value mismatch',0,1) which results in the following text being generated 'Integer value mismatch - Unexpected Result. Expected: 0. Actual: 1'
The helper functions do not alter or change the basis under which TSQLUnit operates, and so they should install and work happily within existing TSQLUnit installations. Download the
TSQLUnit Helper Functions.
I have also provided a
script containing sample TSQLUnit tests - one coded to pass, one coded to fail, both making use of the
tsu_CheckValues_Int.
In another post I will go into the other changes I made, and the recommendations for testing we came up with as a result of this exercise.
Labels: ilp, SQLServer2000, SQLServer2005, TSQLUnit
// posted by Jane @ 1:57 PM
Comments:
Thursday, March 20, 2008
Ideas and Learning project
One of the new initiatives at
Madgex is the introduction of the Ideas and Learning project. This is a cross between the Google 20% initiative and the
Pixar University initiative. Out Ideas and Learning project gives us 35 days per year (roughly 15% of our working time) to developing our own ideas and learning. That covers building prototypes of new ideas, learning about a new technology, trying out something that we've been meaning to attend to, or learning new soft skills.
Yesterday I attended two internal workshops. The first was an hour long session on "Stress Management" which covered both the physical and emotional responses to stress and how the body/brain hasn't evolved sufficiently to allow for different types of stresses to be handled in different ways - we're still hard wired to run away from woolly mammoths, so when we feel stressed our senses become more acute, our heart starts pumping, our blood goes to our legs so we can start running, and our brain gets less blood. We learnt a technique for meditation which I'll give a try to help focus the brain on the present, rather than it over analysing stuff.
The second was a session on "Zen and the craft of software development" which was a whistle stop tour through some history of development covering the
different paradigms, comments vs documentation, problem solving and including lots of hints and tips for development.
Both of these sessions were useful, in very different ways, and I can see that I'm going to gain a lot from this new initiative.
Labels: ilp, madgex
// posted by Jane @ 1:04 PM
Comments: