Archive for General

Going Digital At Home – Part 1

May 4

We have a lot of disparate sources of media around our home. DVDs, CDs, VHS, downloaded content, mp3s, etc. I find it to become more and more of a hastle running around finding the media I want, and then finding the device that can play that. Plus with 3 kids running around it is inevitable that their (and sometimes my) optical media gets scratched or damaged.

To that end I have decided to try and go completely digital in our home and felt that documenting it may be of help to others.

Infastructure:
Wireless network (802.11g)
3 televisions
2 original xboxes
1 xbox 360
1 server (more on this later)
multiple client laptops

Goal:
-Have all media centralized
-Have a backup of all media (if I had to do this all over again I would cry)
-Have different media available from different terminals (kids television should not be able to watch adult shows)

Requirements:
The first step here was to get a central computer that will store all the media. This computer should have the following:
-Lots of storage
-A DVD and or Blue Ray player
-Have some sort of hard drive redundancy
-Enough CPU power to convert videos on the fly (A Pentium III 700Mhz is the bare minimum you would want)
-Enough techincal knowhow to install an operating system, install software, and install hardware into a computer.

To do this I took an old server I had (but a desktop would work just fine) and installed two 2TB drives into it (at the time of writing they cost only $150 each). I also installed Windows Server 2008 R2 onto it but any OS of choice should do.

The biggest difference between my setup and the average user is that my media server has a builtin SATA raid card which I configured to mirror the drives (so I only have 2GB of storage but when (not if, when) one fails I can plunk in another and be on my way). If you don’t have hardware RAID and don’t want to purchase it you can actually setup a raid in software. Setting up a software raid can be a bit tricky but I found a great article about it. The only thing I would change is to give more than 10GB to windows / programs (at least 40GB nowdways I would think). Trust me in that running out of room on a partition is one of the most annoying things to happen to a person.

Once you have the system setup and running I like to make sure that the drives are actually redundant. I have never ever found that a mirror is not actually working after I set it up but I just like to make sure. To do this I take each hard drive out and slave it into another computer and ensure that they both have the same data on it (just a quick check to make sure that the folder structures are copied to each). Once that is done I put them both back in and ensure the mirror is functioning (sometimes it may detect they are out of sync and need to resync the array). The other way to do this is to remove one drive from the server, turn it on, make sure it works, then repeat with the other drive. This process will require a resync of the array which is time consuming. It took at least 15 hours to resync my 2TB array.

That is about it for now. In the future we will talk about software on the server, ripping DVDs and CDs, and how to watch/listen to this stuff on you TVs and computers effectively.

Filed Under: General

Passing Parameters to a target in MSBuild

Apr 29

On our current project we are using MSBuild to build our application. This is my first time using MSBuild other than just tinkering and I have found it…. challenging to say the least. A lot of my challenges are lack of knowledge but the other half is the language itself.

The most recent challenge I wanted to write about was calling a target multiple times. Our scenario is this: We have to generate a batch file for each environment we are going to install in with environment specific settings. The issue I had was that for each environment we had that we were copying and pasting the steps and changing values for each environments. While this worked, as the number of environments grew the size of the build task grew and got harder to modify as requirements changed.

Ideally what we would have is a task that would generate a batch file based on a set of parameters that we could just call out to so I built this:

   <Target Name=”BuildBatchFile “>
    <Copy SourceFiles=”install.bat”
                 DestinationFiles=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                
ContinueOnError=”false” 
                 SkipUnchangedFiles=”false” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{ENV}”
                           ReplacementText=”$(ENV)” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{VDIR}”
                           ReplacementText=”$(VDIR)” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{INSTALLDIR}”
                           ReplacementText=”$(INSTALLDIR)” />
  </Target>

So this copies my template install.bat to install.[ENVIRONMENT[.bat and then does all the string replacements on it.

The issue is how to invoke this task with different sets of data. My first thought was this:

<CallTarget Targets=”BuildConfigFile” />

Unfortunately, there is no way to pass parameters to a target. The only way to do that is to call MSBuild and set the parameters passed to MSBuild (this does feel wrong but I am not sure of a better way to do it so far)

<Target Name=”BuildDeploymentPackage”>
    <MSBuild Projects=”$(MSBuildProjectFile)”
                      Targets=”BuildBatchFile “  
                      Properties=”BATCHENV=ALPHA;ENV=ALPHA;VDIR=PASIPrep;INSTALLDIR=C:\inetpub\wwwroot\MyApp;” />
    <MSBuild Projects=”$(MSBuildProjectFile)”
                       Targets=”BuildBatchFile ”
                        Properties=”BATCHENV=SYST;ENV=SYST;VDIR=MyApp;INSTALLDIR=C:\inetpub\wwwroot\MyApp;” />
    <MSBuild Projects=”$(MSBuildProjectFile)”
                       Targets=”BuildBatchFile “ 
                       Properties=”BATCHENV=TRAINING;ENV=TEST;VDIR=MyApp;INSTALLDIR=C:\inetpub\wwwroot\MyApp.TEST;” />
  </Target>

The above target calls MSBuild to call its own build file and run the BuildBatchFile target with a set of parameters.

Hope this helps (or someone shows me a better way to do it)!

 

 

 

Filed Under: General

Testing Your Configuration

Apr 16

One common issue of team development is sharing configuration files. If a developer is testing something out and changes a value and then accidentally checks that file in it affects all developers.

There are a few approaches to solving this issue:
1) Be very careful and disciplined.

+Simple
-SImple to forget

2) Have a web.config.template under source control that developers copy to web.config and not include in source control.

+Prevents checkins of web.config files that affect other people
-Developers need to manually update their config files if a new value is added/removed/or the default updated

3) Have a build script task to generate a config file on demand.

+Changes are easily propagated through the script
-If a developer mucks with the build script and checks it in then we have the same problem (but less likely to happen)

4) What we are trying. Unit test the configuration to make sure it is correct.
+web.config is under source control
+changes are caught by a test. If it is meant to be distributed to all developers then the test should be updated as well
-have to write a test for the configuration (not a big minus in my opinion)
-If you have different config settings for the test project than the actual project then this will not work

In order to test a config file though we need to be able to load that config file! In our case we are testing a web.config and nunit is expecting a app.test.dll.config file. The easy way around this was to copy the web.config from our application to the proper folder and name with a pre-build event:

copy $(SolutionDir)\App.Service\web.config $(ProjectDir)\bin\App.Test.dll.config /y

Now my tests use that config file to assert that the settings are proper. The big downside to this approach is that it will overwrite the app.config file that you may already have for your test which may not be desirable.

Alternatives:
1) Parse the XML of the config file you want to test and verify
2) Load and unload and external config file in a test (I started with this and could not get it to work)

Filed Under: General

Team City Build Versioning

Jan 19

One of the great things about continuous integration is that we can increment our assemblies version number with each build. For our project we also apply a label to our source code repository every time we build a deployment package. This allows us to get the version of source code from the exact point in time that the msi was built.

One of the issues we ran into was that we have three build configurations:
1. “CI” This gets run on every checkin of code
2. “Deploy – ALPHA” This is run manually to deploy to our alpha test environment
3. “Deploy – ALPHA & BETA” This is also run manually and this deploys the same version to both the alpha and beta test environments

The issue we ran into is that each configuration has its own build number that is incrementing so if we ran “Deploy – ALPHA” 10 times we would have v 1.10.0.0 in ALPHA. If we then ran “Deploy – ALPHA & BETA” for the first time suddenly ALPHA now has v1.1.0.0! Obviously this is not very intuitive. In the end we added in the version number from our source code repository into our build numbers for both deploy configurations. Now we get build numbers like this: 1.46347373.0.0

The way we did this was by using the vcs variable in team city: 1.{build.vcs.number.TheNameOfVCSRoot}.0.{0}. The last digit is still an incrementing counter in case you re-run the build that something still increments even though the version in source control has not changed.

Filed Under: General

Remote MSI Execution

Jan 18

One of the things we have started doing as part of our process is having a build script that creates our deployment package in an automated fashion. We then tied that into our build server so that from one click anyone could create the package. The issue is that we have several test environments and copying the setup.msi file to multiple servers and installing it is a time consuming pain. To streamline our deployment we created a vbscript (yes, it was painful) to remotely uninstall previous versions and then install the new version of the msi. Here is the script currently:

strComputer = “mytestserver”

Wscript.Echo “Getting WMI Object”
Set objWMIService = GetObject(“winmgmts:” & “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2″)

Wscript.Echo “Finding Previous versions”
Set colSoftware = objWMIService.ExecQuery (“Select * from Win32_Product Where Name = ‘My First Setup Project’”)
For Each objSoftware in colSoftware
    Wscript.Echo “Uninstalling a previous version”
    objSoftware.Uninstall()
Next

Wscript.Echo “Getting Software Object”
Set objSoftware = objWMIService.Get(“Win32_Product”)

Wscript.Echo “Installing”
errReturn = objSoftware.Install(“c:\builds\MyFirstSetupProject.msi”, “TARGETENV=DEVL”,True)

Wscript.Echo “Install status: ” & errReturn

In order for this to work the msi must be copied to the remote machine to work. I tried connecting to a central network share but it did not seem to work for me. The script needs a bit of work but now we can deploy to the environments we want updated in a couple of minutes instead of the 15-20 minutes it took us before.

Filed Under: Agile, General

Return To Blogging

Jan 17

I am finally finding some time and desire to write again. Life has been busy with my both my company and my family expanding. It feels like things are starting to get back to normal again so I should be writing more frequently.

Some of the things I have been working with that I hope to write about:

  • nHibernate / fluent nHibernate / Linq to nHibernate
  • WPF
  • Click once
  • Silverlight
  • A fluent .NET build langauage called fluent-build
  • Being a lead on a project
  • Multithreading
  • Caching of large amounts of data
  • Threat modeling
  • Other security items
Filed Under: General

Edmonton Code Camp: Call For Speakers

Aug 6

Edmonton Code Camp is happening again this year and we are looking for speakers! Topics are wide open. That means ANY language, ANY technique, or ANY technology.

When: September 19,2009
Where: Grant MacEwan Downtown Campus, Edmonton, Alberta

Please submit talks to dave@solidhouse.com by August 15, 2009

Filed Under: General

Book Review: Brownfield Application Development

Aug 6

I was asked to review the soon to be published Brownfield Application Development by Kyle Baley and Donald Belcham. For those who have not heard the term, a brownfield application is one that already has some code developed but is usually not complete. A lot of developers are brought into projects like this and therefore have had no say on the techniques and tools to start developing the application. This book covers how to make an existing application better, more testable, and easier to work with in a simple and accurate fashion.

The book is split into two sections, the first one: The Ecosystem covers important topics like version control, testing, continuous integration, and defect tracking. The chapters were well written with no bias towards a particular technology (although the pros and cons are discussed of some systems). Baley and Belcham accurately describe how to setup an ecosystem that allows you to develop and maintain a code base well into the future.

The second section: The Code, hits home with how to bring good quality code practices into the code base. I found over and over again that the authors hit on all the problems I have seen working on brownfield and legacy code bases and great recommendations on how to overcome them.

One of the key things the authors hit on is how to minimize dependencies in your code base. Tightly coupled code is both hard to change and test which makes minimizing the dependencies very important. The best part of this book is that they have a separate chapter for reducing dependencies internally and on external systems. I find this to be the most important topics that this book covers.

I wish I would have had this book ten years ago and not had to learn these lessons the hard way. The book so accurately describes the pain points of software development and how to eliminate or mitigate those issues. The authors have obviously gone through the same learning curve that I have and have perfectly summarized their years of experience in an easy to consume format.

Filed Under: General

Oracle Raises Prices

Jul 27

Oracle has announced that they are raising the prices on the Oracle 11g database. MS has kept the price of SQL Server 2008 the same (for now). I am still amazed that Oracle charges what they do when you can almost get two MS SQL Server licences for the price of one Oracle license. While Oracle has been shown to perform faster than SQL Server 2008 I would much rather have a system that is easier to work with and cheaper than one that I find dificult to work with and out of my clients budget range.

Here is a price comparison (NOTE: prices are based on manufacturers suggested price at the time of this writing)

Oracle   Microsoft  
Standard Edition One* 5,800    
Standard Edition* 17,500 Standard Edition  5,999
Enterprise Edition  47,500 Enterprise Edition   24,999

*the differences I could find between these two editions was that Standard Edition One allows 2 sockets and Standard Edition allows 4 sockets plus clustering and workload management.

 

Filed Under: General

Starting Up The Development Webserver From An Integration Test

May 31

Often you will have tests written that hit a service that is going to be hosted via IIS. On our development box we will probably be using the development webserver that ships with Visual Studio. Often the development webserver is not running when we start our tests which causes a failure. To combat that we have all our service tests inherit from a base class that starts up the webserver if it is not already running. This gives us consistent testability:

    [TestFixture]
    public class ServiceTestBase
    {
        private Process process;
 
        [TestFixtureSetUp]
        public void Start()
        {
            if (!IsWebServerAlreadyRunning())
            {
                const string x86Location = @"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\9.0\WebDev.WebServer.Exe";
                const string non64BitSystemLocation = @"C:\Program Files\Common Files\microsoft shared\DevServer\9.0\WebDev.WebServer.Exe";
 
                //create a normalized path (Path.GetFullPath() will remove our ..\ characters
                string physicalPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "..\\..\\..\\Dispatch.Service\\"));
 
                process = new Process();
                if (File.Exists(x86Location))
                    process.StartInfo.FileName = x86Location;
                else if (File.Exists(non64BitSystemLocation))
                    process.StartInfo.FileName = non64BitSystemLocation;
                else
                    throw new FileNotFoundException("Could not find WebDev.WebServer.Exe");
                
 
                process.StartInfo.Arguments = string.Format("/port:{0} /virtual:\"\" /path:\"{1}\\\"", 50256, physicalPath);
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.UseShellExecute = false;
 
                // start the web server
                process.Start();
            }
        }
 
        private static bool IsWebServerAlreadyRunning()
        {
            Process[] processes = Process.GetProcessesByName("WebDev.WebServer.Exe");
            if (processes.Length > 1)
                return true;
            return false;
        }
 
        //if you want to stop the webserver after each test fixture is run then 
        //uncomment the following 
 
        //[TestFixtureTearDown]
        //public void TearDown()
        //{
        //  if (process != null)  
        //      process.Kill();
        //}
    }
Filed Under: General