Extracting files from an SVN repository backup

Extracting files from an SVN repository backup

Say you’ve got a backup of an old SVN repository. You want to grab a couple of files, but the backup looks like this:

C:myrepo_backup    format    README.txt    conf    dab    db    hooks    locks

You figure you probably need to run some fiddly import commands to restore it into a live SVN server so you can connect and browse it right? Wrong! SVN has a feature that makes this incredibly easy: the client can browse and check out directly from a backed up repository on your own local file system.

All you need to do is use the file:// URL scheme and point to your backup, for example:

svn checkout file:///C:/myrepo_backup myrepo

And yes if you’re using Windows, TortoiseSVN does support this — so you can very easily use Repo-browser to explore any SVN backup. Very handy!

SqlDropDatabase, SqlCreateDatabase MSBuild tasks

SqlDropDatabase, SqlCreateDatabase MSBuild tasks

When working with SQL, I often find I need to quickly spin up/tear down local developer database instances – for example, setting up a clean environment for integration tests on the build server, or blowing away test data.

To help make this easier, here are a couple of MSBuild tasks I wrote that allow you to drop an existing database:

<SqlDropDatabase ConnectionString="Server=.SQLEXPRESS;Database=AdventureWorks;Integrated Security=SSPI;"                 Database="AdventureWorks" />

… and to create a new (empty) one.

<SqlCreateDatabase ConnectionString="Server=.SQLEXPRESS;Database=AdventureWorks;Integrated Security=SSPI;"                   Database="AdventureWorks" />

It’s also sometimes helpful to be able to parse individual individual keys out of a connection string (e.g. the the database name). This can be very tedious with RegexMatch/RegexReplace, so I wrote a separate MSBuild task to do it:

<SqlParseConnectionString ConnectionString="Server=.SQLEXPRESS;Database=AdventureWorks;Integrated Security=SSPI;">    <Output PropertyName="myDb" TaskParameter="InitialCatalog" />    <Output PropertyName="myServer" TaskParameter="DataSource" />    <Output PropertyName="myTimeout" TaskParameter="ConnectTimeout" /></SqlParseConnectionString><Message Text="Parsed the $(myDb) database on server $(myServer) with timeout = $(myTimeout)." />

Implementing access control in a tiered application

Implementing access control in a tiered application

Recently I have been working on a reasonably-large ERP system that supports around 2,000 users. The system has approximately forty access control groups to which individual users can belong. Each of these groups grants or restricts access to parts of the system. For example, a user may be allowed to edit the price of a product if they are in the SalesManagers group. If they are in the InventoryManagers group, they can edit the number of items in stock. If they are in the Admins group they can do everything.

public class User{        // A list of groups the user belongs to.        public List<string> MembershipGroups { get; };         // ... etc}

To handle all these access groups and their associated rules, a form page’s load method contained several screenfulls of business logic to determine which elements should be editable by the user and which should not.

Here’s a simple example of what it might look like on an EditProduct page:

public class EditProductPage : Page{        // Form elements.        private TextBox ProductName;        private TextBox Price;        private TextBox NumberInStock;         public void InitializeForm()        {                if (CurrentUser.MembershipGroups.Contains("Admins"))                {                        // Admins can change anything.                        ProductName.Enabled = true;                        Price.Enabled = true;                        NumberInStock.Enabled = true;                }                else if (CurrentUser.MembershipGroups.Contains("SalesManagers"))                {                        // SalesManagers can change the product's price.                        ProductName.Enabled = false;                        Price.Enabled = true;                        NumberInStock.Enabled = false;                }                else if (CurrentUser.MembershipGroups.Contains("InventoryManagers"))                {                        // InventoryManagers can change the inventory levels.                        ProductName.Enabled = false;                        Price.Enabled = false;                        NumberInStock.Enabled = true;                }                else                {                        // Regular users can't do anything.                        ProductName.Enabled = false;                        Price.Enabled = false;                        NumberInStock.Enabled = false;                }                 // ... other complex business logic        }}

Now this is all good and well, but what happens if someone is a member of SalesManagers and InventoryManagers? Or if we add rules related to editing certain types of products? What happens if we need to make another form? This code will grow exponentially and start to spaghetti out of control.

I believe there are two fundamental problems with this design. Firstly, it is not clear what the different access groups mean in the context of the form. For example, if you’re a member of the InventoryManagers group, which fields should be editable and which should be locked? These rules are probably defined clearly in a requirements document somewhere, but are difficult to understand from reading the source code.

The second problem is that these rules are implemented at each point they are consumed, i.e. in the presentation layer. Each form is free to access and interpret what each group means. This logic clearly don’t belong here: a form page should only know how to hide and show elements! On the other hand, it seems this responsibility doesn’t lies exclusively with the business layer either, as it relates to form-specific elements. So where should it go?

In a well-designed application, the relationship between group membership and access privileges would not be exposed to the UI. Instead, we should define a list of easily-understood permission flags that have direct meaning to consumers of our model. Each of these flags will explicitly define what a user can and cannot do. They must be as simple to understand as possible.

public class AccessPermissions{        // Correct: these flags can be applied directly to a form.        public bool CanEditName { get; };        public bool CanEditPrice { get; };        public bool CanEditNumberInStock { get; };         // Incorrect: this flag is too vague.        bool IsAdmin { get; };}

We can then add these permissions to our User class:

public class User{        // A list of groups the user belongs to.        public List<string> MembershipGroups { get; };         // The user's access permissions.        public AccessPermissions Permissions { get; };         // ... etc}

Setting these flags may involve complex and conditional business logic, which is now removed from the presentation layer. These simplified flags can then be directly used by the form’s Supervising Controller:

public class ProductEditFormController : ISupervisingController         // The passive view for the current form.        private IEditFormView Form;         // Set up form state.        public void InitializeForm()        {                AccessPermissions permissions = CurrentUser.Permissions;                 if (permissions.CanEditName)                        Form.ProductName.Editable = true;                 if (permissions.CanEditPrice)                        Form.Price.Editable = true;                 if (permissions.CanEditNumberInStock)                        Form.NumberInStock.Editable = true;                 // ... etc        }}

Privileges should be separated amongst multiple classes, specific to different areas of functionality. For example, you might provide a UserPermissions class for a user management form:

// Permissions related to user management.public class UserPermissions{        bool CanEditName;        bool CanEditMembershipGroups;        bool CanDeleteUser;}

By removing access level-related logic from the point of consumption and declaring them as explicit, immediately-usable flags, we can make it much easier for developers to consistently apply access control. Removing potentially complex business logic from the presentation layer cuts down on code duplication (and bugs). The overall quality of the system improves.