Tuesday, June 16, 2015

Converting from MSTest to NUnit

Ever since I was converted to the one true gospel of Test-Driven Development in 2008, I have had to convert test projects from MSTest to NUnit and back a few different times. After my last time having to do it, I decided it was time to testify.

The Facts

MSTest and NUnit have different names for the decorations on the test classes & methods:

MSTest Attribute
NUnit Attribute
Purpose
[TestMethod]
[Test]
Identifies of an individual unit test
[TestClass]
[TestFixture]
Identifies of a group of unit tests, all Tests, and Initializations/Clean Ups must appear after this declaration
[ClassInitialize]
[TestFixtureSetUp]
Identifies a method which should be called a single time prior to executing any test in the Test Class/Test Fixture
[ClassCleanup]
[TestFixtureTearDown]
Identifies a method in to be called a single time following the execution of the last test in a TestClass/TestFixture
[TestInitialize]
[SetUp]
Identifies a method to be executed each time before a TestMethod/Test is executed
[TestCleanUp]
[TearDown]
Identifies a method to be executed each time after a TestMethod/Test has executed
[AssemblyInitialize]
 N/A
Identifies a method to be called a single time upon before running any tests in a Test Assembly
[AssemblyCleanUp]
 N/A
Identifies a method to be called a single time upon after running all tests in a Test Assembly

Source: Comparing the MSTest and Nunit Frameworks, by Naysawn Naderi, 1 Feb 2007.
This article contains some information that is no longer accurate, particularly in regards to the NUnit test runner, but this chart is still correct.

There are a few other minor syntactical differences to be aware of:
  1. Methods decorated with [ClassInitialize] in MSTest must have the signature
    public static void MethodName(TestContext context)
    while methods decorated with [TestFixtureSetUp] cannot have any arguments.
  2. MSTest's Assert and NUnit's Assert both have a method IsInstanceOfType(), but the order of parameters is reversed between frameworks.
    MSTest: void IsInstanceOfType(object actual, Type expectedType)
    NUnit:    void IsInstanceOfType(Type expected, object actual)
The Editorial

The debates over whether to use MSTest or NUnit typically revolve around three factors:
  1. Speed
  2. Integration
  3. Ease of use
People are pretty evenly split as to which one is actually faster. Personally I've found that so many factors affect this (the version of Visual Studio being used, the complexity of the tests, the framework being targeted, the version of NUnit) that we have to just call this one a tie.

When it comes to integration, if you're using Resharper, then it's a moot point. Resharper can run MSTest and NUnit tests in the very same test run seamlessly, and with a far superior interface to MSTest. And if you're not using Resharper, well then I just don't know how you do it. I had to go without Resharper for a week at a new job once, and it was like trying to run in waist-deep water. Everything took five times as long, and my confidence in my code was significantly reduced.

MSTest requires at least twice as many keystrokes to write tests than NUnit - everything is more verbose, with no additional benefit (see the difference in method signatures above for a minor example). Plus, NUnit can do this:

[TestCase("ConnectionStringA")]
[TestCase("ConnectionStringB")]
public void CreatePendingPaymentTest(string connectionName)
{
 //setup

 Repository classUnderTest = new Repository(connectionName);
 classUnderTest.CreateRecord();
 
 //assert
}

[TestCase] allows you to run the same test with different settings/inputs.
You can accomplish the same thing with MSTest by writing multiple tests that call the same method with different parameters, but again, more work to get the same result.

So, with speed being equal, integration being a non-issue, and NUnit the easier to use, the verdict is clear: use NUnit. It's available through NuGet when you need to add it into your solution, and you can learn more at NUnit.org. Enjoy!

EDIT (6/18/2015):
The syntactical differences section omitted an item that is now included.

Tuesday, February 3, 2015

Learn the Rules so you can figure out who's breaking them

99.99 percent [of subatomic interactions] are explainable ... Spending your time exploring each particle trail will lead you to conclude that all the particles obey known physics, and there's nothing left to discover ... Most stars are boring; advances comes from studying the weirdies - the quasars, the pulsars, the gravitational lenses - that don't seem to fit into the models that you've grown up with ... Collect raw data and throw away the expected. What remains challenges your theories.
- Clifford Stoll, in The Cuckoo's Egg
The Cuckoo's Egg is an amazing book - it's a memoir, a techno-thriller, and a manifesto all in one. It recounts how, in the mid-1980s, an astronomer-turned-sysadmin at UC Berkley stumbled across a hacker in their system, and upon tracking down the intruder, ended up catching a ring of KGB agents in their first real stabs at cyber-espionage! It's a must-read for anyone who's ever going to write code, and just a darn good read for everyone else.

The quote above (from chapter 3) is a very insightful one because it tells us, in essence, that the really useful details are in the edge cases. Stoll's first hint that something was up was a $0.75 discrepancy in an accounting system. No one suspected foul-play, and in most scenarios, the bean-counters would just write this off and be done with it. But Stoll and his co-workers decided to dig, and found a rabbit hole so deep it literally did go all the way through to the other side of the world.

It's a principle that technology professionals need to keep in mind at all times. Yes, you will encounter that case eventually. The numbers will get that big. That reference will find some way to be null. There will be someone with 25 dependents. It's not enough to make sure it works for the most typical cases. Of course that's where to start coding, and where to focus the majority of the testing. But you can't ignore the weirdo edge cases - finding and understanding them can expose hidden problems, as well as opportunities. A lot of revenue can be lost by systems that are leaky around the edges, and a lot of unrealized revenue can be tapped by looking in the same places. Don't assume there aren't any outliers, because there always are. Find them, and either bring them in line, or exploit the opportunity they present you!

And the thing about outliers is that they can always pop back up. You think you've fixed that bug, only to see some more examples of it weeks after the release. You write off a 'harmless' variation each month, only to realize it added up to a pretty big loss by year's end. Again, always assume there are outliers, and put checks and balances in your systems to find them. Sometimes this mean making sure your test suite is robust enough; other times it means having an independent audit system.

This is especially important these days. I'm not suggesting that most weird events can be explained by a hacker, but you never know. Anyone who reads the news knows you can't be too careful. Don't assume your security is good enough! If something seems suspicious, figure it out! Outliers can just be bugs, but they can also be attacks.

Very few people are actually lazy, but we can all be lulled into a false sense of security. Just because the fire alarm isn't going off doesn't mean there aren't any fire hazards. We don't need to be paranoid, or rule-bound, but we do need to be vigilant and thorough. How one maintains such an attitude is probably the subject for a whole book and in the end is different for everyone, but it's a skill that technology professionals must develop.

Tuesday, February 11, 2014

WCF Data Member Order

One element of SOAP in WCF that is often overlooked is Data Member order. We need to stop and remind ourselves from time to time that SOAP is just XML, and that a data contract is not actually code, but rather an abstraction of XML (or JSON). The WCF Test Client can actually give us a good illustration of this. When you have a operation that you are going to call, the standard view is "Formatted", like so:


But there is also an "XML" view, which gives you this:


This is what actually gets transmitted to the service; this is the 'real' message.

WCF can actually be very picky about the order of the elements in a SOAP message: if the message being sent and the service receiving it don't agree on the data member order, the message won't deserialize properly. Worse, it won't give you any errors, but your object will only be partially populated. Now, if you publish your service, the client generates the service reference, and no one ever changes either, then this isn't an problem. But services do change - even adding a new element where you can accept the default value can change message order expectation. And if the client is not using WCF on their end (e.g., because they're using Java, or are a legacy system), then agreement between client and service cannot be assumed.

The good news is you can control the order of elements in a message.

The code for the previous examples is this:

[DataContract]
public class DeleteClaimRequest
{
 [DataMember]
 public int ClaimId { get; set; }

 [DataMember]
 public string RequestorUserName { get; set; }
}

Right now, the data member order is merely alphabetical (note: not the order of declaration). But let's say we wanted to enforce that the RequestorUserName came first. We can do that by modifying the code like so:

[DataContract]
public class DeleteClaimRequest
{
 [DataMember(Order = 2)]
 public int ClaimId { get; set; }

 [DataMember(Order = 1)]
 public string RequestorUserName { get; set; }
}

The message would then be formatted like so:

<s:Envelope 
   xmlns:a="http://www.w3.org/2005/08/addressing" 
   xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">
       http://company.com/service/2/IDataReceiver/DeleteClaim
    </a:Action>
  </s:Header>
  <s:Body>
    <DeleteClaim xmlns="http://company.com/service/2">
      <message xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <RequestorUserName>john</RequestorUserName>
        <ClaimId>123</ClaimId>
      </message>
    </DeleteClaim>
  </s:Body>
</s:Envelope>

Easy, right? Yes, but only because there's no inheritance involved. Consider this contract:

[DataContract]
public class SetCredentialsRequest : ManagementRequest
{
 [DataMember(Order = 1)]
 public string ProviderUserID { get; set; }

 [DataMember(Order = 2)]
 public string ProviderPassword { get; set; }
}
 
[DataContract]
public class ManagementRequest
{
 [DataMember(Order = 3)]
 public string AssociateUsername { get; set; }
}

The result is not what you expect. WCF will actually want the message to be in this format:

<s:Envelope 
    xmlns:a="http://www.w3.org/2005/08/addressing" 
    xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">
       http://company.com/service/2/IServiceManager/SetProviderCredentials
    </a:Action>
    <a:MessageID>urn:uuid:3c9a3661-0c33-461e-adca-08076696742d</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
  </s:Header>
  <s:Body>
    <SetProviderCredentials xmlns="http://company.com/service/2">
      <request xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <AssociateUsername>john</AssociateUsername>
        <ProviderUserID>user123</ProviderUserID>
        <ProviderPassword>41aer45b1</ProviderPassword>
      </request>
    </SetProviderCredentials>
  </s:Body>
</s:Envelope>

This is because WCF always puts the elements from a base class first (see this MSDN article). No matter what value you put as Order for AssociateUsername, WCF will always expect it to be first. And just to make things to even more confusing, the "Formatted" view of the WCF Test Client will show the message like so:


The solution? Use interfaces!

If you change the code like so:

[DataContract]
public class SetCredentialsRequest : IManagementRequest
{
 [DataMember(Order = 1)]
 public string ProviderUserID { get; set; }

 [DataMember(Order = 2)]
 public string ProviderPassword { get; set; }

 [DataMember(Order = 3)]
 public string AssociateUsername { get; set; }
}

public interface IManagementRequest
{
 string AssociateUsername { get; set; }
}

then it will produce the desired result:

<s:Envelope 
     xmlns:a="http://www.w3.org/2005/08/addressing" 
     xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">
       http://company.com/service/2/IServiceManager/SetProviderCredentials
    </a:Action>
    <a:MessageID>urn:uuid:67ddfa83-88a7-407e-a4b9-12c314a05905</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
  </s:Header>
  <s:Body>
    <SetProviderCredentials xmlns="http://company.com/service/2">
      <request xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <ProviderUserID>user123</ProviderUserID>
        <ProviderPassword>41aer45b1</ProviderPassword>
        <AssociateUsername>john</AssociateUsername>
      </request>
    </SetProviderCredentials>
  </s:Body>
</s:Envelope>

C# doesn't care what order the members of an interface are placed on the inheriting object, and WCF serialization doesn't deal with a base interface the way it deals with a base class, so you are free to specify the order explicitly and definitely. This way you're able to achieve type unity/inheritance while still being able to specify the necessary order. And because the order is specified in the derived object instead of by the interface, AssociateUsername could have a different order in every class that inherits from IManagementRequest. (Generated service reference code is smaller and less complex as well.) As an added bonus, interfaces generally make for better inheritance chains, as a class can implement many interfaces but only one base class. (Base classes have their place for separation of concerns in code, but again data contracts are not code!)

So, long story short:
  • Always explicitly specify data member order to avoid serialization problems.
  • Use interfaces when creating data contract inheritance chains.
  • When you change a contract, be mindful of how member order changes may affect clients/impact message serialization.

Wednesday, March 13, 2013

How to get a list of objects from all databases on a SQL Server host

SQL Server has a very complete metadata catalog, which comes in handy a lot more often than you might think. One limitation of it though, is that all the metadata is stored on a per-database basis, which makes it difficult to correlate information between databases. (The metadata is stored in system tables in each individual database.)

Last week, I needed to gather a list of stored procedures from multiple databases. I found some solutions online, but most of them involved spitting out multiple results sets, which wasn't particularly useful for me.  After poking around for a little while, I came up with the following solution:

USE [master]
GO

DECLARE @SchemaName VARCHAR(50) = 'dbo';
DECLARE @sql AS VARCHAR(MAX) = '';

SELECT 
 @sql = @sql +
 'SELECT ''['+name+'].['+@SchemaName+'].'' + name AS procedure_name ' +
 'FROM ['+name+'].sys.procedures ' + 
 'WHERE schema_id = '+ 
  '(SELECT schema_id ' +
  ' FROM ['+name+'].sys.schemas ' + 
  ' WHERE name = '''+@SchemaName+''') ' +
 'UNION ' + CHAR(10)
FROM sys.databases
WHERE [state] = 0

SET @sql = LEFT(@sql, LEN(@sql)-8)

EXEC(@sql)
GO

(The sys.databases table is available in every database, not just master. Operating out of a system database just seemed to make more logical sense since the whole point is to gather data from 'user' databases.)

Essentially, what this is doing is generating the following statement for each database:

SELECT '[db_name].[dbo].' + name AS [procedure_name]
FROM sys.procedures 
WHERE schema_id =  
 (SELECT schema_id 
  FROM sys.schemas
  WHERE name = 'dbo')

and then UNION-ing all the results together. It involves a little 'magic' in that @sql = @sql + (stuff) statement, which basically makes it so each row emitted by the SELECT statement adds to the value of @sql (which is why it must be pre-populated as '' instead of NULL.)

I want to emphasize that dynamic SQL like this is risky - like any other kind of SQL statement building, it opens you up to SQL injection attacks, even if contained in a stored procedure. As a script that you store on your machine and run ad hoc though I think it's a good solution.

Monday, March 11, 2013

Complex .NET config transformations

In my previous post, I talked about (web).config transformations: how great they are and how they can be enhanced beyond the 'base install.' Continuing on, some of those enhancements later led us to some even more useful and advanced actions.

Using multiple configuration files in a .NET project is not the simplest thing to achieve. There are different mechanisms for including/merging files, but each have their limitations. One way is to specify that a section comes from another file, like so:

<connectionStrings configSource="otherfile.config"/>

The limitation with this approach is that the entire section must come from that other file. There is no 'merging' of elements; you couldn't add any additional elements to the <connectionStrings> section in this scenario.

You can get around this by importing the other config this way instead:

<appSettings file="otherfile.config">
   <add key="PagesToHide" value="AdminPage" />
   <add key="ExternalLinksToHide" value="Utilization Report" />
</appSettings>

The limitation with this approach is that this kind of import is not supported for all types of config sections:  <system.servicemodel>, for example, can't be used this way. (Also, some code inspection tools, like ReSharper, don't know how to parse this syntax.) And both these approaches force the imported file to be only that one config section; you couldn't have an <appSettings> section and a <connectionStrings> section in an external file and merge/import them both into your config.

In some scenarios, these limitations are not a problem. Both of these approaches have served us well (on a limited basis) in the past. Recently however we had the need to include a non-trivial set of configuration values into the config of multiple applications, most of which were already using web.config transformations. I generally assume that, as a developer, if I have copied and pasted something then I have failed. I wanted to find a more elegant, maintainable solution than just making each development team copy and paste the values into their individual base and transformation configs.

The solution we eventually came up involves a multi-step transformation. Don't be daunted by that "multi" though - it's actually quite a simple implementation.

We started by renaming the web.config (and its children web.debug.config & web.release.config) to web.base.config (children: web.base.debug.config & web.base.release.config). The content of these files we left untouched. We then added the files gateway.debug.config and gateway.release.config to the project. Each one looked something like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <add key="Thumbprint" 
         value="52CD92D192786742DA589FEA4C83719DA43E82C9" 
         xdt:Transform="Insert" />
    <add key="Version" 
         value="4" 
         xdt:Transform="Insert" />
    <add key="ConnectionString" 
         value="Data Source=db_host;Integrated Security=True" 
         xdt:Transform="Insert" />
  </appSettings>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_Gateway"
                 closeTimeout="00:00:10" 
                 openTimeout="00:00:10" 
                 receiveTimeout="00:00:10" 
                 sendTimeout="00:00:10"
                 xdt:Transform="Insert">
          <security mode="Transport" />
        </binding>
      </basicHttpBinding>
      <wsHttpBinding>
        <binding name="WsHttpBinding_Gateway"
                 closeTimeout="00:00:10" 
                 openTimeout="00:00:10" 
                 receiveTimeout="00:00:10" 
                 sendTimeout="00:00:10"
                 xdt:Transform="Insert">
          <security mode="Transport">
            <transport clientCredentialType="Windows"
                       proxyCredentialType="None"
                       realm="" />
            <message clientCredentialType="Windows"
                     negotiateServiceCredential="true" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://fake.url/GatewayService/4/a.svc/basic"
          binding="basicHttpBinding" 
          bindingConfiguration="BasicHttpBinding_Gateway"
          contract="namespace.interface"
          name="GatewayTransport_1"
          xdt:Transform="Insert" />
      <endpoint address="https://fake.url/GatewayService/4/a.svc/roles"
          binding="wsHttpBinding" 
          bindingConfiguration="WsHttpBinding_Gateway"
          contract="namespace.interface2"
          name="GatewayRoles_1" 
          xdt:Transform="Insert" />
    </client>
  </system.serviceModel>
</configuration>

The important parts to notice here are the xdt:Transform="Insert" attributes in each XML node. With XML transformations, it's possible to add (insert) elements as well as modifying and deleting them. (The xmlns attribute in the <configuration> element is also very important; without it Visual Studio doesn't know the file is a transformation document.)

The 'magic' comes in with a build step added to the project file:

<Target Name="BeforeBuild">
   <TransformXml 
       Source="web.base.config"
       Transform="Gateway.$(Configuration).config"
       Destination="obj\$(Configuration)\web.intermediate.config" />
   <TransformXml 
      Source="obj\$(Configuration)\web.intermediate.config"
      Transform="web.base.$(Configuration).config"
      Destination="web.config" />
</Target>

Now when the project builds, the compiler takes the base config and transforms it with the appropriate gateway config. Since the gateway config only has addition transformations, this effectively works like a merge of the two files. Then, the build configuration-specific transformation is performed, updating the elements that originally came from the base config to their build-appropriate values. This produces the web.config for the build configuration the solution was built in.

Like approaches discussed in the previous article, this solution is very seamless because it happens at compile-time, so you're able to validate the result at any point, and the web.config that IIS wants is always there. Plus, the gateway configs could be dropped into any project with ease because they just add on to what's already there. The one drawback is that you do have to rebuild to get IIS to pick up configuration file changes, whereas usually you can just save the file and refresh the web page. (This also makes the Visual Studio context menu item 'add config transform' not work, but then it doesn't always work anyway, and adding files to a project is a pretty trivial task.)

The example used here is for a web.config, but this should all work exactly the same with an app.config (so long as the build task is imported - see previous article.)

The possibilities presented by this technique are endless - you could do some pretty complex and powerful things by chaining transformation steps together. You don't want to have too many config files, but if you need to bring separation of concerns or just better readability to your application configuration, this is a powerful and elegant way to do it.

Wednesday, January 30, 2013

A simpler approach to .NET Config File Transformations

One of the nicer features of ASP.NET 4.0 is the concept of configuration file transformations. In case you are not familiar with it, here's a quick two-paragraph overview:

ASP.NET websites almost always need a different configuration for each deployment environment. The development/test configuration will differ in important ways from the staging configuration, and again from the production/live configuration. However, these differences are often only a smart part of the configuration file: a few URLs, server names and assorted settings. Before 4.0, the typical way to manage this was to maintain a separate, but 90% identical, web.config for each environment, and somehow make the right file the 'real' web.config at deployment. Keeping the files in sync was not a trivial task, especially with large projects. We had one application with a config that was well over a thousand lines, and the various environment 'editions' have gotten so out of sync with each other that we spent an embarrassing amount of time squashing bugs that would only manifest in one environment (which of course was usually production).

Web.config transformations brings some relief to this problem. With this feature, you have the web.config, and then it has several child files, one for each build configuration. The primary web.config contains all the information, and then each child file contains instructions for modifications. For example, the primary web.config might contain a section defining the test database connection string, and then the child file web.release.config contains an instruction to replace that section with the production database connection string. When you publish the website, it will transform the primary web.config based on the child config file that corresponds to the build configuration being published, resulting in a file that is valid for the environment. (These 'instructions' are an XML transformation language developed by Microsoft.)

As useful as this feature is, there are some difficulties.

The main difficulty is that transformations are not created at build time. This can make them a little hard to validate, because you have to go out and use a secondary tool or script to execute the transforms and check them over. You can do this from the command-line like so:

msbuild /nologo /target:TransformWebConfig /p:Configuration=Release IISHost.csproj

This will create the the transformed config (for the Release build configuration) in obj\Release\TransformWebConfig\transformed\Web.config.

In the spirit of making this a usual part of the build process, we attempted to include this as a post-build event. However, because this MSBUILD task actually compiles the project, this creates a circular dependency where the project is built, and then the post-build event kicks off, which builds the project a second time, which kicks off the post-build event, which keeps looping back on itself infinitely until your computer crashes.

Not generating the transforms at build-time also causes issues for deployment. Transforms are generated when a website is published, but the Publish mechanism is not the best or preferred way to deploy. In enterprise environments especially, the deployment team typically does not have development tools such as Visual Studio or MSBUILD installed, and generally just wants to have a folder of files they can copy to the correct directory. (Publish also does not lend itself to managing backups, versioning, or rollbacks.) So build engineers and deployment teams have to manually execute the transform, and then go through and copy and rename files just as they did before ASP.NET 4.0.

The third issue is that it's also only available for web.config files, not for app.config files. Now, there are plug-ins that add this feature for non-web projects, such as SlowCheetah. SlowCheetah is a good solution, but I was always hopeful I could find a simpler, more integrated approach. A number of articles, especially this one, told me it was possible, but their solutions were more complex than I really wanted. They did however guide me to this conclusion:

It is possible to execute the transform as a native part of the build by adding some elements to the project file. These elements cannot be added through the Visual Studio GUI (as far as I know), so you do have to manually edit the project file, but these additions are very small, simple bits of XML, so it's not too daunting.

In a website project, at the bottom of the file (just before the </Project> element), add the following:

<Target Name="AfterBuild">
    <TransformXml Source="web.config"
                  Transform="web.$(Configuration).config"
                  Destination="obj\$(Configuration)\web.config" />
</Target>

The target name is very important; that's the part that tells the compiler to run the TransformXml task as an after-compile task. (Because it is not making an external, recursive call, the afore-mentioned infinite loop condition is not created.) Once this section is added, every build will produce, in the obj folder corresponding to the build configuration just compiled, the transformed web.config! The beauty of this solution is that the transformed config is always available when you want to validate it (or when build engineers or deployment teams need to copy it) but the default, development web.config remains in place and untouched.

TransformXml is included by default for website projects. You can do the same thing for app.config files, but you have to explicitly import the task in non-web project files. You can do this by including the following line before the <Target> element:

<UsingTask 
   TaskName="TransformXml" 
   AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" 
/>

(The DLL referenced here is included as part of the Visual Studio install, so you shouldn't have to add any packages or features. It does not need to be included in the Project References either.)

Being able to automate the configs in this manner has been very helpful for us. In my next post, I'll go into detail about how we were able to leverage this knowledge to accomplish even more advanced tasks.

EDIT: If you have other post-build tasks that rely on the transformed web.config, you should use "BeforeBuild" as the target name. There appears to be a slight delay between the build finishing and the final file being written out. To avoid any race conditions, use "BeforeBuild" instead of "AfterBuild".)

EDIT 2 (7/15/2016): I have modified the <UsingTask> path to use $(VisualStudioVersion) so the project file is more maintainable.

Sunday, October 28, 2012

Software Development Roles

In software development, there are four major stakeholders, or roles to play: the customer, the architect, the engineer, and the operator.
  • The Customer: The customer is most typically the business analyst, executive, or client that is driving the production of software. They are the people who write the checks.
  • The Architect: The architect is the person or persons responsible for designing how the system(s) work. They must take a holistic view and are responsible for guiding software to a place that is reliable, testable, efficient, and de-coupled.
  • The Engineer: The engineers are those who actually build the software, who sit down and write code based on the customer's needs and the architectural designs.
  • The Operator: Operators come in two very different classes: end-users and operations groups. If you release software for public consumption, your operator is the end-user. If however your software runs on company servers and/or workstations, then the systems personnel are the operators.
The ideal scenario, the sweet-spot where quality, sustainable software is developed, is where each of these different roles work in concert with all the others. The problem of course is that they often don't. The customer is impatient or bombastic, demanding features and deadlines that turn the architects and developers into slaves to his whims, too harried to do their jobs correctly. The architect is overbearing and tyrannical, over-planning the system to the point that it can never be completed and insisting all development pass through him. The engineers are slap-dash, churning out code without regard to system performance, readability, or bug count. The operators are too cheap, unwilling to provide enough servers to handle the load gracefully.

Hopefully no one has ever been in a position where all four of these sentences were true (or at least didn't have to work there long), but everyone's been involved in a job or project where at least one of them was. When one group wields too much say over the software development cycle, problems ensue. Each role should have autonomy in their own domain - their working environment should not be dictated to them by another role. However, for each role to enjoy such independence, there has to be a certain amount of give and take between them. For instance, if your engineers want to develop ASP.NET websites, the operators can't very well insist on Apache servers. If your operators are largely iMac owners, it would be unrealistic for the engineers to decide to write C# desktop apps. If the architect thinks it would be swell to use SharePoint, it's not his/her place to demand that the customer abandon the current CMS system they've come to know and love. Deciding how a piece of software (or software system) comes together requires negotiation and collaboration between the different groups.

One mistake commonly made is to assume that these roles have to be separate people. Naturally, in small companies, particularly start-ups, a small group of IT people will wear multiple hats. Freelancers, consultants, and one-man-IT-shops will often wear the architect, developer, and operator hats simultaneously and exclusively. There is a tendency, though, as the company grows, for these roles to become different departments. There's not necessarily anything wrong with that. But how a company sets up its reporting relationships should not determine how software development roles are filled. Software quality is improved and innovation is fostered when individuals who are engineers 90% of the time are allowed to be architects when the time is right. Architects who step into developer shoes produce more realistic systems. Operators who can be the customer sharpen system requirements. Fostering an environment where this kind of 'cross-pollination' is looked on favorably should certainly be a priority for all involved parties.

I once worked in the Information Systems Division of a Fortune 100 company. They had a lot of clumsy processes and a lot of the folks who worked there weren't standouts in their fields. But their environment was set up in such a way that each role had the autonomy they needed. An architectural group had created an overall vision for how the various systems should fit together, and the development groups were expected to follow that vision. However, inside their own domains, development teams had enormous flexibility in choosing the programming language, OS platform, and design patterns to use. The operators, the infrastructure teams that maintained the servers and terminals that ran this software, had a finite list of platforms and runtimes they would allow, but it was a long list, and anything on that list they would fully support.

My current job employs a much higher caliber of person, and has a much better development life cycle. They have, however, struggled with finding this correct balance between the stakeholders. Despite the flaws of that previous position, I find myself looking back at how they did things as a guide in this area. On paper, this sounds like a rather abstract and theoretical discussion, and in some IT shops it might be. But when this balance is off and/or these roles are not clearly defined, your workday can quickly transform into a series of turf wars. If you find yourself getting into that kind of situation, it's time to take a step back, define, and balance. We didn't, and it went badly: we thought we'd 'won' the turf war, only to have the problem come back at us sideways and make things worse. Don't let this happen to you!