Jane's Technical Stuff

Wednesday, January 14, 2009

Review: Microsoft Visual Studio Hints and Tips


In September, I attended Sara Ford's session at Remix UK on Visual Studio IDE Tips and Tricks which was a really useful session in showing me just how little I knew about the shortcuts available within the Visual Studio IDE. Like many .Net developers, I've been using Visual Studio in one incarnation or another for years now and haven't necessarily spent time familiarising myself with the efficiency updates, new features and new keyboard shortcuts. I found the presentation format quite hard to gather the shortcuts from though and ended up trawling through Sara's blog of tips to get further details on the ones that looked handy (incremental find for instance).

I volunteered to do a session for the developers at Madgex as part of the ILP programme to pass this useful material on, and to encourage myself to find more tips. In preparing the talk (which is tomorrow) I've made a lot of use of a copy of Sara's book Microsoft Visual Studio Tips: 251 Ways to Improve Your Productivity as well as suggestions from the team.

I hadn't got very far into the book before I found myself changing settings in Visual Studio and trying things out - always a good sign. This is definitely a book to have next to you whilst you're sitting at your development machine and not one for general reading as I found some of the tips needed to be tried to make complete sense of them. I've also found myself trying out a lot of them on different environments - Visual Studio 2005, Visual Studio 2008 and SQL Server Management Studio (which doesn't get a mention in the book, but has quite a lot of tips that just work) to see what works in which scenarios, and which will prove useful to me and how I develop code. I've found the tips to be good-sized nuggets of information, almost all of which cover one scenario in isolation. They are easy to read and follow, and contain good text instructions with screen shots when they are helpful.

I'm not sure how much long term use this book has, I suspect it is one to have in the office shared amongst a group of developers so that everyone can have a browse, pick some efficiencies and pass the book on rather than one to dip into on a regular basis. Despite the fact that the tips from the book are also on her blog, the book makes them a lot more accessible and easier (at least for me) to read and implement. So, in summary, a worthwhile addition to a development library.

Labels: , ,

// posted by Jane @ 5:55 PM   save to del.icio.us

Comments:

Saturday, December 13, 2008

SQL Coding Dojo 2


Yesterday I led the the second SQL coding dojo held as part of the Madgex ILP programme. As with the first one, I chose a puzzle from my copy of Joe Celko's SQL Puzzles and Answers. This time I chose one called One in Ten which I described as follows:

During a data migration exercise a table has been created which takes the outputs of an array and flattens them into a table named Dojo2 which is defined as:

Id INTEGER – Primary Key
F1 INTEGER
F2 INTEGER
...
F10 INTEGER

Produce a list of rows which have exactly one non zero value in the columns F1 to F10 using any method you like – select, views, creating new tables etc

As with last time, I've put a copy of the SQL file I produced to create the tables and populate the data here, and this time I've also provided two of the solutions from the book here.

Learning from last time's feedback I had a proper keyboard plugged in to my laptop this time. Other than that I ran it very similarly. There were only 3 attendees this time, so at each time we had one driver and 2 co-pilots as this seemed more practical. All of them had keyboard time, and all had co-pilot time. Again like last time I provided a word document detailing the table layout, the SQL used to create and populate the data, and the expected results - this can be downloaded here.

During the practice 2 different approaches were tried, one using string manipulation the other using ABS and max value checking. The ABS and max value checking method worked for the first 3 columns and so was assumed that it would work across all 10 columns but the participants got a bit fed up of typing as the method chosen - using lots of CASE statements would have been many lines long on completion :-)

The retrospective raised the following points:
  • Generally the session was enjoyed
  • Each participant learn something and found some areas to follow up on - mainly SIGN, ABS and PIVOT
  • The screen resolution of the laptop when plugged into the big screen was an issue as it was hard to get enough data on the screen at one time - given the number of participants a large standard monitor would have been better
  • Participants felt that it was good to watch how people tried to solve the problem and learnt from others approaches
As with last time, it was enjoyable for me to watch, and I learnt both from setting up the problem in the first place trying out the provided solutions, but also from watching my colleagues try different approaches.

Labels: , , ,

// posted by Jane @ 9:00 AM   save to del.icio.us

Comments:
I have a second edition of SQL PUZZLES in print now. The Japanese and Chinese translations are better than the English edition because the translators came up with more answers and some new material on their own!

If anyone came up something new, send it to me for a possible third edition.
 

Tuesday, September 30, 2008

SQL Coding Dojo


Last week I led a SQL based Coding Dojo as part of the Madgex ILP programme. A lot of ILP sessions are in a presentation format, and I wanted to do something with a bit more, or in fact a lot more, attendee participation. I've been interested in the idea of deliberate practice for a while, and Richard has been to quite a few coding dojos and so I figured it was time to give it a try. Shortly after I'd decided to do one, I attended a Skills Matter evening and stumbled across Ivan Sanchez, who blogged about Starting a Coding dojo which helped me get my thoughts in hand.

I chose to use SQL as the area to practice, mainly because it is an area I am really familiar with and so could help out if necessary. Also I have a copy of Joe Celko's SQL Puzzles and Answers which provided me with a great collection of puzzles to practice with.

I chose a puzzle called Double Duty which is described as follows:
A person may have more than one role. The roles are defined as follows:
O – Officer
D – Director

The PersonRole table is defined as:
PersonName VARCHAR(50)
RoleCode CHAR(1)


Produce a list of People and their roles where they are either Officer or Director, and where anyone with both the O and D role is represented once as B – Both.

I've put a copy of the SQL file I produced to create the tables, and populate the data here, so feel free to take a look.

I opened the session by explaining what a dojo was (a training hall for practice in the martial arts), what a coding dojo was (a practice area for coding skills) and introduced the problem domain (I provided print outs of the table structure, data and expected results). I then introduced the roles we were going to use - driver and co-pilot - and the rules we were going to adhere to. In our main meeting room we have a large plasma screen and so I connected this to my laptop so that the audience could see exactly the same as the driver and co-pilot. I provided a couple of SQL books and a SQL Server cheatsheet for reference.

After the initial self-consciousness had gone, the pairs settled into the idea pretty well, and it was interesting to watch the different pairs interact and form new (rapid) working relationships. There were 7 participants, and each spent 5 minutes as the driver and 5 minutes as the co-pilot. By the end of the session there were 4 solutions produced which meant that the group as a whole felt that they'd achieved something. We ran a quick retrospective at the end of the session and the following were the major points:
  • The audience found a certain amount of frustration by not being able to help, and not being able to shout out suggestions.
  • At least one person acting as the co-pilot found it hard to articulate what needed to be done.
  • At least one person admitted to finding it hard to think without having their fingers on the keyboard.
  • At least one person learnt something about SQL.
  • Quite a few people found a laptop keyboard hard to use, so a proper keyboard would have helped.

As a result of the success of this one, I've booked in another one for a couple of months time - again SQL based but I'm also thinking of making use of TDD Problems for another practicable skill.

Labels: , , ,

// posted by Jane @ 8:28 PM   save to del.icio.us

Comments:

Wednesday, August 27, 2008

Review: Clone Detective


The Morning Brew #162 mentioned a tool Clone Detective which
is a Visual Studio integration that allows you to analyze C# projects for source code that is duplicated somewhere else. Having duplicates can easily lead to inconsistencies and often is an indicator for poorly factored code.


Today, a colleague and I spent some ILP time investigating the tool to determine whether it would help us in the Madgex environment or not.

We tried the tool out on a couple of projects, but due to it being a Visual Studio 2008 only plug-in our options were a bit limited. After installing the plug-in, the next thing we did was watch the video. This gave us a good overview of how it works, and where to find it (hiding under View -> Other Windows -> Clone Explorer). During the video it explained that effectively this tool breaks code down into a series of tokens, and then looks for other pieces of code which can also be broken down into the same series of tokens. The terminology took a little while to get a grasp of - there are clones and there are clone classes. A clone class is a series of tokens which is/may be repeated throughout the solution. A clone is an instance of this fragment. So, if there was a line of code which did something like a = b + c, the clone class would be [var] = [var] + [var], and the clones could be lines of code which are a = b + c or d = e + f (irrespective of whitespace or variable names etc).

It works across an entire solution, so we set it running and looked at the clones it found. Unfortunately, a lot of the clones that were detected for us were false positives - like properties which when tokenised are the same, but which can't really be re-factored. Additionally, some of the clone classes that it detected, are actually multiple presentations of the same code. For instance, one file I looked at had the following lines all marked as clones of different clone classes:
  • lines 20 - 43
  • lines 20 - 59
  • lines 24 - 43
  • lines 24 - 44
  • lines 37 - 59
which basically tells us that the area of code from lines 20 - 59 should be re-factored into (probably) one new piece of code which can then be re-analysed to find out if other re-factorings are also worthwhile.

The interface is easy to get to grips with, and is accessed either via its own panels (Clone Explorer, Clone Intersections and Clone Results) or by an indication in the code window with a context sensitive menu item Find Clones, or Show Clone Intersections. Clicking on an item in the explorer allows you to navigate into more detail and find the clone class or find all instances of it. In a big solution, with a lot of clones (false positives or otherwise) the right click to get clone class listing can take quite a while - in the order of 10 - 20 seconds - which can result in lots of re-right-clicking when one is impatient. This may indicate a problem with scalability.

The tool would have proved a lot more useful to us with a few extras:
  • Ability to ignore properties
  • Ability to list all clone classes at once, rather than having to right click on a file in the Clone Explorer and choose Show Clone Intersections. Then picking a file in there and right clicking to select Clone Class x -> Find All Occurrences
  • Ability to mark clone classes as "ignore" so it doesn't report on them again

So, our summary is, a nice idea but gives too many false positives and isn't refined enough at the moment to be of use within our environment on a regular basis. It may, however, still be useful as a one-off exercise (with patience) to find the key areas that should be addressed. In a less complex code base it might be worth another look. Additionally, if when working on some code we detect something that looks like its been copied and pasted, then it might well be worth running Clone Explorer to find other areas that could benefit from our refactoring.

This leaves us with the question, how else can we detect clones in our code base? Until we find something else, this is better than nothing. Does anyone have any suggestions of other tools which could address this area?

Labels: , ,

// posted by Jane @ 5:26 PM   save to del.icio.us

Comments:
Hi Jane,

I am one of the developers of the clone detective detection algorithm, which is part of the ConQAT (http://conqat.in.tum.de) analysis toolkit. (The plugin you reviewed is an integration into Visual Studio to make it easy to use in the .NET community, but the actual detection is performed by ConQAT).

Thanks for the review! I would like to comment on some of the feature requests you mentioned, since some of them are already supported by ConQAT, even though they are not already included in the VS integration.

1.) Tailoring: detection can be tuned, i.e. to ignore properties or exclude overlapping clone classes as you mentioned in the post.

2.) Overview: ConQAT's primary use case is continuous analysis. To be able to be run non-interactively, it writes its results to HTML pages. These pages also include lists of all clones, treemap-visualizations that display the distribution of the clones over the system or trend charts to evaluate the development of clones over time.

3.)Blacklisting: clones can be blacklisted, so that they do not show up in future detection runs.

Furthermore, ConQAT supports clone detection for additional languages, more specifically C/C++, VB.NET, Java, Cobol and PL/1. (And a bunch of other analyses beyond clone detection, but this is probably out of scope here)

You can find documentation of ConQAT here http://conqat.in.tum.de and on clone detection specifically here: http://conqat.in.tum.de/index.php/CloneDetectionTutorial. We are still lagging behind on documentation somewhat though, so feel free to contact me if you have any questions.

I hope that helps, Best regards,
Elmar
 

Wednesday, August 20, 2008

SQL Snap


At last September's BarCamp Brighton I saw the CSS Specificity Snap cards and this gave me an idea. So, armed with a concept of showing the different ways of producing the same output using the SQL Server 2005 flavour of SQL I started generating SQL statements. Alex was kind enough to make them pretty, and last week I ran a Madgex ILP session to play.

There are 26 cards in my pack, each card has a SQL statement, and a letter. The letter is used for the crib sheet to allow me to easily spot the matches.



I prepared by producing two piles of 13 cards, with a match in both piles. I then put one pile in the middle of the table face down, and dealt out the rest of the cards to the 5 people who were playing. I placed the 3 spare cards on the table face up so that we could all see them and proceeded to turn them over one by one. When a card was turned over everyone looked at the SQL on the overturned card, and checked their cards and the spare cards to see if there was a match. If a match wasn't spotted then I explained what the SQL was doing, and at only one point did I have to say which letter the matching card would have. During this I had quite a few comments about functions people didn't recognise - especially COALESCE and NULLIF. I also explained some of the performance, and functional differences between the SQL statements when they were seen - so for instance I explained the differences between DELETE and TRUNCATE but I still I have these as a match because they can provide the same result and provided an interesting talking point.

The second game we played was a memory game where I placed all of the cards on the table face down and everyone turned over 2 cards at a time. If the SQL on the cards resulted in the same output, then it was a match and they took the cards away. If they didn't then the cards got turned back over and the next person had a go.

All in all this session took about 30 minutes, and resulted in quite a lot of noise and laughter (so much so that someone came and closed the door of the room we were in).

The following table contains the Letter Code, SQL statement, and the matching Letter code. They are ordered so that the matches are grouped together.
CodeSQLMatch
VSELECT CAST(GETDATE() AS VARCHAR(11))G
GSELECT CONVERT (VARCHAR(11), GETDATE())V
ZSELECT name FROM sysobjects WHERE xtype = 'P'Q
QSELECT name FROM sys.proceduresZ
DSELECT sysobjects.name, syscolumns.name FROM sysobjects INNER JOIN syscolumns ON sysobjects.id = syscolumns.id WHERE sysobjects.xtype = 'u'A
ASELECT sysobjects.name, syscolumns.name FROM sysobjects, syscolumns WHERE sysobjects.id = syscolumns.id AND sysobjects.xtype = 'u'D
USELECT getdate()O
OEXEC('SELECT getdate()')U
JDELETE FROM TestT
TTRUNCATE TABLE TestJ
YSELECT ISNULL(NULL,1)W
WSELECT COALESCE(NULL,1)Y
PSELECT [name], xtype FROM sysobjects ORDER BY xtypeM
MSELECT [name], xtype FROM sysobjects ORDER BY 2P
HSELECT NULLIF(1,1)R
RSELECT CASE 1 WHEN 1 THEN NULL ELSE 1 ENDH
ISELECT [name], xtype FROM sysobjects ORDER BY 1N
NSELECT [name], xtype FROM sysobjects ORDER BY [name]I
XSELECT CAST(GETDATE() AS VARCHAR(20))F
FSELECT CONVERT (VARCHAR(20), GETDATE())X
SSELECT name FROM syscolumns WHERE id = ( SELECT id FROM sysobjects WHERE xtype = 'u' AND name = 'Jobs' )K
KWITH objects (id) AS
( SELECT id FROM sysobjects WHERE xtype = 'u' AND name = 'Jobs' ) SELECT name FROM syscolumns INNER JOIN objects ON syscolumns.id = objects.id
S
LINSERT INTO Job (JobID, PrimaryJobTypeID) VALUES (1,1)B
BINSERT INTO Job (JobID, PrimaryJobTypeID) SELECT 1,1L
CDECLARE @sMessage AS VARCHAR(20) SET @sMessage = 'Hello'E
EDECLARE @sMessage AS VARCHAR(20) SELECT @sMessage = 'Hello'C

Labels: , ,

// posted by Jane @ 8:17 PM   save to del.icio.us

Comments:

Thursday, August 07, 2008

ILP Time - How did I spend mine?


So, the first period of ILP time is over, and I've managed to use 50-60 hours of my allocation attending workshops, watching presentations, learning stuff and doing ideas project work.
Learning:
  • Started reading through the Opera web standards curriculum to ensure my knowledge was up to date
  • Attended various presentations including: Stress Management, Zen and the craft of software development, Introduction to unit testing with nUnit, CSS3: Third time's the charm, Comet (a presentation by Simon Willson who came in kindly to talk to us), Basic NLP and hypnosis, SQL Server Advanced, Vision and Goal setting, Theories of Management and Javascript inheritance

Ideas:
  • Looked into DBVerse, a database deployment tool, to see if this would help us. Review here
  • Looked into Tarantino, another database deployment tool. Review here
  • Worked with Bruce to start writing a database deployment tool to meet our specific requirements. This is still ongoing and will continue into the next few months
  • Attended Hackday 3 and worked on some keyword searching work with Chris
  • Looked into Stylecop, a code style analyser. Review here

Now I have to start planning out the next years allocation - I'm cashing in a couple of days to attend the ReMix UK conference, I'm going to continue attending Simon's management and leadership courses, as well as his NLP related ones. I'm also hosting 2 sessions in the next month - one which is SQL Snap, based on CSS Specificity snap and one which is an experimental SQL Coding dojo. I'm sure I'll report back on both of these afterwards.

Labels: , ,

// posted by Jane @ 7:41 PM   save to del.icio.us

Comments:

Friday, August 01, 2008

Learning


One of the Madgex value words is Passionate, and this got me to thinking what am I the most passionate about in my working life and it has to be learning. And by that I mean both learning myself and encouraging and enabling learning amongst team members and colleagues.

In Eat that frog - which I'm currently reading - there is a lovely quote
"Continuous learning is the minimum requirement for success in any field"

One of the things I try and do is read a lot, mostly in the form of blogs where I find useful titbits of information, or clues, or things to go and find out more about, but also books relating to more static skills. My google reader list now includes more leadership and time management focussed blogs as well due to my recent role change. I've also cashed in some of my ILP time to follow the Web Standards Curriculum to ensure that I have a full understanding of the implications of web standards.

This also leads to me keeping a keen eye on what is going on event-wise within the community - both locally, here in Brighton, and further afield (well near London main-line stations if I'm honest) - that could form an introduction to new techniques, technologies and methodologies. I've just started sending out a weekly email to Madgex containing all of my finds, so that others can benefit from shared learning experiences. My key resources for this are upcoming searches for Brighton & Hove, geek, .Net, Barcamp, sql, developer along with MSDN events, VBUG events and Skills Matter events.

I'm planning to go to Remix UK in September, which I'm hoping will be a great way to catch up with new technologies and new methodologies. I've been to a WebDD, a DDD and SQLBits community conferences before so it will be great to see how Remix differs.

Labels: ,

// posted by Jane @ 12:27 PM   save to del.icio.us

Comments:

Monday, June 09, 2008

Database Change Management: Tarantino review


Last week, Chris Alcock included a mention of an article .NET Database Migration Tool Roundup in The Morning Brew #109. Both Bruce and I read this and came to the same conclusion, that Tarantino might be worth a look to stop us from continuing writing our own tool to manage the change process reliably. Today we invested some more of our ILP time into examining how it works, and what it does.

Firstly, there isn't much documentation, so we had to fumble around a bit to work out how to use it. I read the wiki page with interest, and found myself agreeing with what was said there. I especially liked the quote:
"Successful database change management requires that a consistent process be applied by all team members. Without a consistent process than the tools provided in this solution will not provide its full value"

We found that this documentation, and the process description validated our aims and thoughts on how the process should work, suggesting:
  • a local database for each developer - this works for me on 2 levels, firstly in the same way that a good developer wouldn't check their code into source control until it was complete, the database changes shouldn't affect anyone else until this stage either, and secondly database changes get tested by other team members
  • changes are implemented as SQL scripts
  • there is a predefined order in which the SQL scripts should run

We aren't, initially, looking at a tool that needs to integrate with an automated build environment, so we didn't need a lot of the features that Tarantino offers. Instead we concentrated on the Tarantino.DatabaseManager.exe application and worked with that. The result of this is that some of our requirements aren't met by the DatabaseManager but may be met by some of the other aspects of Tarantino.

Tarantino ui

The user interface is fairly self explanatory, and there is a .config file associated with it to pre-fill the default values. There are 4 possible actions: Create, Update, Drop and Rebuild.
  • Create - the default. This will create the database identified in the Database field (I didn't find how you specified the settings for database creation during my 1.5 hour investigation, but I'm sure it's there somewhere). It will then update the database identified in the Database field according to scripts found in the Update sub-folder of the folder specified in the Script Folder field, running them in alphabetical order.
  • Update - This will update the database identified in the Database field according to scripts found in the Update sub-folder of the folder specified in the Script Folder field, running them in alphabetical order if they haven't already been reported as run in the table of scripts
  • Drop - This will drop the database identified in the Database field
  • Rebuild - This will combine the Drop and Create tasks above.

DatabaseManager uses file naming as a convention for determining the order in which the update files will run - the recommendation for naming is 0001_Script.sql, 0002_Script.sql etc however during our investigation we discovered that we could leave Copy of 0001_Script.sql hanging around and this would just get appended to the list in alphabetical order. We were somewhat concerned that during the development process amongst a team, more than one person could be working on database updates at a time (and when using a local database, there is no guarantee that anyone else would know about it) which could mean, at best, two files with the same prefix, i.e. 0003_AddTableArticles.sql and 0003_FixBug12122.sql and at worse a source control conflict of 0003_Script.sql. This is where naming conventions would obviously come into play. During our discussions we liked the idea of some form of dependency mapping - i.e. 0003_AddTableArticles.sql is dependent on the change 0001_Script.sql. This would obviously help us to ensure that errors with code vs database versioning could be avoided. This isn't provided within Tarantino.

DatabaseManager records the scripts run in a table named usd_AppliedDatabaseScript in the database that is being worked on. This means that all actions will not be recorded in perpetuity as choosing the action Drop or Rebuild from the user interface would remove this table as well as all others, and the database itself. One of our preferences is to have a central database per server which records the scripts run - this would mean that the dba team would be able to see, at a minimum, what scripts have been run and when. We also feel that having some form of contact details associated with the script is a useful addition - this seems to be covered in the deployment tool that is included in Tarantino, but not on a script by script basis.

One of the process pre-requisites mentioned for Tarantino is:
"Create a change script that wraps all of the database changes into a single transactional change script. A Tool like Red Gate SQL Compare makes this a 30 second operation."
This unfortunately means that error handling is poor and transaction handling is non existant. One of our tests was to create a file containing invalid SQL amongst the (valid and not applied) change scripts. The error was reported in the output window amongst nAnt exception reporting - making it quite hard to track down. When the error occurred, then data relating to the preceding SQL files in that Update batch will remain in the database but the subsequent files will not even be called - this leaves the database in a state of uncertainty. The table usd_AppliedDatabaseScript gets a row added for any previous files successfully completed, but the Version gets left as NULL. When I corrected the SQL and re-ran the process, the Version column gets updated to match the version number for the rest of the files successfully applied in the batch. This results in different date/time stamps on the rows, but the Version number being the same which makes me wonder if tracking the version history of the database is then subject to a certain amount of interpretation. In addition, selecting the action Create from the user interface when the database already exists results in an exception being raised - in my opinion this should be handled via some defensive SQL coding.

Note: All tests were carried out on a Windows XP laptop running a local installation of SQL Server 2005.

We have previously, also looked at DBVerse to meet our requirements. As neither tool satisfies what we're attempting to do, we'll continue writing our own but this was a worthwhile diversion as it really validates our thoughts on process vs program, and how that process should look.

Labels: , ,

// posted by Jane @ 6:56 PM   save to del.icio.us

Comments:

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 StyleCop

I 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

StyleCop 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.SourceAnalysis
where 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: ,

// posted by Jane @ 1:35 PM   save to del.icio.us

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 TRAN
and the
  IF @@TRANCOUNT > 0
    COMMIT TRAN

so 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 TRAN


which 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 TRAN

To 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 TRAN


No new row is added as a result of this action as now all actions are covered within a transaction.

Labels: ,

// posted by Jane @ 1:03 PM   save to del.icio.us

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 TRAN

the 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 TRAN

which 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: ,

// posted by Jane @ 6:01 PM   save to del.icio.us

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 ApplyAllUpdates

A 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 ApplyAllUpdates

The 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 rowsID    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: , , ,

// posted by Jane @ 1:09 PM   save to del.icio.us

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: , , , ,

// posted by Jane @ 1:57 PM   save to del.icio.us

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: ,

// posted by Jane @ 1:04 PM   save to del.icio.us

Comments:

Brighton Bloggers   This page is powered by Blogger. Isn't yours?   rss Sussex Digital - focusing on the Sussex digital community