Notes from Daily Encounters with Technology RSS 2.0
 
# Sunday, March 22, 2015

Paul Swartout: Continuous Delivery and DevOps - A Quickstart GuideDevOps is a topic we have all been hearing a lot about lately. When I was contacted by Packt publishing whether I am interested to review their latest book on the subject (Continuous Delivery and DevOps - A Quickstart Guide - Second Edition by Paul Swartout), I decided to grab the opportunity and learn more about the subject in a more structured way than blog posts and podcasts can provide.

It turned out this was mostly a book about soft skills, with technical topics not being in the forefront. There were a couple of tools mentioned, and the importance of monitoring and metrics was strongly pointed out, but I expected more than that. I might be a bit biased due to my engineering background, though.

A common thread through all the chapters is a story about a fictional company which successfully implemented DevOps. It serves as an example of the journey and the practices involved. Probably the most important message it tries to get across, is the fact that there's no such thing as DevOps in a box: you can't buy it or just hire an expert - everyone needs to live it and breathe it.

In the end the book falls a bit short and remains just an overview of methodologies and approaches, with lots of pointers to further resources. Although, not really actionable on its own, it is still a good starting point to learn about DevOps: what it is and why you might want to take on the task of implementing it.

The book is available on Amazon and sold directly by the publisher.

Sunday, March 22, 2015 1:43:26 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Personal | Reviews
# Sunday, March 15, 2015

David Boike: Learning NServiceBus - Second EditionI'm fairly familiar with the architecture of distributed applications and the concept of a service bus, though I don't have any first hand experience with NServiceBus. When I got the offer to review Learning NServiceBus - Second Edition, written by David Boike and recently published by Packt Publishing, I gladly accepted the opportunity to learn more about this premium service bus implementation for .NET framework.

The book starts out with a short step-by-step tutorial for creating a simple distributed application using NServiceBus, but it quickly moves on to a more advanced overview of the platform as a whole and the principles it builds on. Although most of the book revolves around development, it doesn't constrain itself to it. Towards the end, operational topics are covered as well: application configuration, administration, monitoring, scaling; showing the scope of the platform, being much more than just a development framework.

The author doesn't focus on NServiceBus alone; instead he gives quite a lot of attention to the basics of messaging and service buses, doing his best to provide incentives for a distributed application design. No matter the previous experience, by the end of the book the reader should be acquainted enough with NServiceBus, to recognize a project requiring it. When that happens, this introductory book won't be enough to get the job done. Still, once you've read it, it will be much easier to depend on other (mostly online) resources, listed in the book. I also like, how the author pointed out the most important changes in the latest version of NServiceBus, which will prove more than useful when reading older blog posts about it.

Whether you're starting to learn about NServiceBus, considering the adoption of distributed architecture in a .NET framework based project, or just want to know what NServiceBus is about, you should read this book. You never know when this knowledge might give you a different perspective on the challenges in your daily work.

The book is available on Amazon and sold directly by the publisher.

Sunday, March 15, 2015 3:40:59 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET | Personal | Reviews
# Sunday, March 8, 2015

Writing a build script for my DocPad project was only the first step before finally setting up a configuration in TeamCity which automatically runs on every commit. Although there is no built in support for Grunt in TeamCity, it was easy enough to find a plugin for it, so that I didn't have to invoke it from command line. Plugin installation was straightforward as usual for TeamCity plugins. Of course, the correct version of Node.js must also be installed on the server which is hosting the build agent.

The first step in the build configuration must install the NPM dependencies which are not committed in the source control repository. Thanks to the already mentioned TeamCity.Node plugin this can be easily done by just selecting the Node.js NPM runner and calling it with install command as always. As long as Node.js is properly installed (and TeamCity was already restarted after the installation to pick up new machine-wide paths), it just works.

Since I already had a build script ready, I only had to run my existing Grunt tasks (generate, test and deploy) as the next 3 steps in my TeamCity configuration. Again, it was enough to select Grunt as the runner and enter the name of the task for each of the steps. As suggested in the Grunt documentation, I selected the runner to use the NPM package from project instead from a system-wide installation. It came as a slight surprise to me that this meant grunt-cli will have to be installed as a local development dependency in the project as well.

The next stumbling block on the path to a working build in TeamCity were globally installed NPM packages - DocPad to be exact. In the recent versions of Node.js NPM is globally installing packages per user and not per machine. This avoids the need to have administrative privileges when globally installing packages, but requires them to be installed separately for every user which will need them.

In the case of TeamCity build agents, this means that it is necessary to globally install the required packages also for the user account which is being used by them. As long as they are running as regular users and don't use any of the system accounts, this shouldn't be a problem: you can always log in with that account and install the missing packages.

For agents, using the Local System account, as configured by default, it is possible to start a command prompt for that account using PSTools and install the package from there. This isn't enough, though, because the install location (%WINDIR%\System32\config\systemprofile\AppData\Roaming\npm) in this case isn't added to path, as it is for the other users. Since running services with Local System account isn't a good idea any way, I would suggest to use a dedicated service account for the agents and avoid the issue altogether.

The steps above were enough to achieve a working build inside TeamCity, but in case of failed builds the output only included the name of the step which failed without any additional information:

[14:44:54]   Step 3/4: Test (Grunt)
[14:44:55]      [Step 3/4] Step Test (Grunt) failed

For cases like this TeamCity supports service messages in special format which are automatically parsed and aggregated to the build overview page. To make matters even simpler, there's already a Grunt task available which adds support for them to any existing Grunt task. The usage of grunt-teamcity is really simple:

  grunt.initConfig(
    {
      teamcity:
        all: {}
    }
  )

  grunt.loadNpmTasks('grunt-teamcity')

  grunt.registerTask('generate-TC', ['teamcity', 'generate'])
  grunt.registerTask('test-TC', ['teamcity', 'test'])
  grunt.registerTask('deploy-TC', ['teamcity', 'deploy'])

To add emitting of TeamCity service messages to other tasks, teamcity task always needs to be executed before the other ones. To avoid its extra output when running Grunt from command line, I decided to add a simple wrapper for each of the tasks which runs teamcity as the very first task, and changed build configuration in TeamCity to start these wrapper tasks instead of their original counterparts. Now the output provides much more information in case of a failure:

[15:47:11]   Step 3/4: Test (Grunt) (1m:08s)
[15:47:16]      [Step 3/4] Resource not found linked from http://localhost:9778/ 
                           to http://localhost:9778/blog/archive1.html
[15:47:16]      [Step 3/4] Status code: 404
[15:48:19]      [Step 3/4] Aborted due to warnings.
[15:48:19]      [Step 3/4] Done, but with warnings.
[15:48:19]      [Step 3/4] Step Test (Grunt) failed

The same report is also included in the mail sent from TeamCity every time a build fails. In most cases the included information should be enough to fix the build even without looking at the complete log in TeamCity. I'm quite satisfied with that.

Sunday, March 8, 2015 8:07:01 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | Grunt | Software | TeamCity
# Sunday, March 1, 2015

Since my first DocPad project is slowly nearing completion, I decided it's time to create a configuration for it on my continuous integration server. I'm a big proponent of the idea that the build server should only run steps which can easily be repeated on the developer's machine, because it reduces dependency on a specific build server and makes troubleshooting the builds much easier.

This made it clear that I'll need to write a build script first. Although I had no previous experience with any JavaScript based make tools, I soon decided in favor of Grunt because of the large collection of tasks available for it, which should make it fairly easy to achieve everything I wanted to:

  • generate the static site from my DocPad project,
  • detect broken links in the site, and
  • deploy static files to the web server.

Grunt turned out to be really easy to get up and running thanks to its getting started guide. Once I completed it, I already had a working build script which cleaned the output directory out in order to remove any obsolete files from the previous site generation. Since I already used CoffeeScript with DocPad, I decided to stick with it in Grunt as well:

module.exports = (grunt) ->
  grunt.initConfig(
    {
      clean: ["out"]
    }
  )

  grunt.loadNpmTasks('grunt-contrib-clean')

  grunt.registerTask('default', ['clean'])

To make it work, I only had to install 2 NPM packages as development dependencies:

npm install grunt --save-dev
npm install grunt-contrib-clean --save-dev

Generating the site with DocPad turned out to be a bit more difficult. I had no luck finding a Grunt task for it, so I had to settle with a different solution: I took advantage of the fact that setting up DocPad on the machine includes installing it globally so that docpad command is always in path. This made it possible to use shell task to invoke docpad directly:

module.exports = (grunt) ->
  grunt.initConfig(
    {
      clean: ["out"]
      shell:
        docpad:
          options:
            stdout: true
          command: "docpad generate --env static"
    }
  )

  grunt.loadNpmTasks('grunt-contrib-clean')
  grunt.loadNpmTasks('grunt-shell')

  grunt.registerTask('generate', ['clean', 'shell:docpad'])
  grunt.registerTask('default', ['generate'])

The first part of my build script was now complete.

link-checker task was probably the main reason I chose Grunt as my make tool in the first place. Still; to make it work, I had to have the site running in a web server. Fortunately there's a Grunt task for that as well: connect can run a web server for the duration of the build script - exactly what I needed.

I quickly configured additional 2 tasks in my build script. I set the port to 9778 to match DocPad's default value when invoking DocPad run:

  grunt.initConfig(
    {
      connect:
        docpad:
          options:
            port: 9778
            base: './out'
      'link-checker':
        docpad:
          site: 'localhost'
          options:
            initialPort: 9778
    }
  )

  grunt.loadNpmTasks('grunt-contrib-connect')
  grunt.loadNpmTasks('grunt-link-checker')

  grunt.registerTask('test', ['connect:docpad', 'link-checker:docpad'])

This a time I had 2 minor setbacks before I finally got it work:

  • link-checker task had problems with minified JavaScript and CSS files in my project and kept finding bogus missing resources. After inspecting the files I decided to exclude them from the validation. This proved to be an easy task using the configuration options of node-simplecrawler, which is being used under the covers:
  grunt.initConfig(
    {
      'link-checker':
        docpad:
          site: 'localhost'
          options:
            initialPort: 9778
            callback: (crawler) ->
              crawler.addFetchCondition((url) -> !url.path.match(/\.min\./))
    }
  )

  • A bug in node-simplecrawler made link-checker impossible to use with the latest version of Node.js (v0.12.0), because there was no way to avoid the following error:

Fatal error: "name" and "value" are required for setHeader().

For now I decided to keep using the previous version of Node.js (v0.10.36). Since the fix for the bug is already available, it shouldn't be long before a new version of the task is available which includes it.

In my case deployment of static files to the web server consists only of copying them to a network share, because both servers are in the same network. This can easily be done using copy task. Grunt can take care of copying to a network share as long as the correct syntax is used. It's also important to preserve the relative folder structure, which can be done using the cwd option. This is the end result in my case:

  grunt.initConfig(
    {
      copy:
        docpad:
          cwd: 'out'
          src: '**/*'
          dest: '//servername/sharename/foldername/'
          expand: true
    }
  )

  grunt.loadNpmTasks('grunt-contrib-copy')

  grunt.registerTask('deploy', ['copy'])

Having a build script with 3 tasks, corresponding to the build steps I wanted to achieve originally, was enough to thoroughly test them. I also managed to fix a couple of existing broken links in the site, thanks to it. I even configured a new internal site on the web server which I can use for testing with different mobile devices on the network. I still had to automate these steps on the build server, but that's already a subject for a different post.

Sunday, March 1, 2015 8:12:48 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | CoffeeScript | Grunt | JavaScript | Software | DocPad
# Sunday, February 22, 2015

One of my coworkers suddenly encountered the following error in a large .NET application we're developing:

'ResourceDictionary' root element is a generic type and requires a x:Class attribute to support the x:TypeArguments attribute specified on the root element tag.

Of course the ResourceDictionary class in question wasn't generic, hence the error made no sense. To make matters worse, no changes were made to the file since it was checked out from source control; and that version of the project compiled fine.

  • We started randomly reverting different changes in the working copy - without success.
  • We tried to compile the same code on a different machine, just to make sure there wasn't something wrong with the developer's copy of Visual Studio - it failed the same way on other machines.

Eventually we ran out of ideas and decided to check whether anyone else has encountered this issue before. Sure enough, we found a MSDN forum post with exactly the same issue. The solution for the problem made no more sense than the problem itself: add the x:Class attribute to the root element as suggested in the error message. Its value doesn't really matter and can be anything.

This was enough to resolve our issue, but I couldn't let the matter rest without investigating it further. After reading the forum thread in detail a couple of times, I started looking for a simple way to reproduce the issue in another project. It turned out you need at least 3 classes in your project:

  • A generic class derived from UserControl:
public class GenericBaseUserControl<T> : UserControl
{
    public T Property { get; set; }
}

  • A custom user control deriving from it:
<genericResourceDictionary:GenericBaseUserControl x:TypeArguments="system:String"
    x:Class="GenericResourceDictionary.CustomUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:genericResourceDictionary="clr-namespace:GenericResourceDictionary"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300">
    <Grid>

    </Grid>
</genericResourceDictionary:GenericBaseUserControl>

  • A ResourceDictionary importing the namespace with the above custom control:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:GenericResourceDictionary">
</ResourceDictionary>

That's enough for the bogus compile error to appear. I know of 2 workarounds to avoid the issue:

  • Remove the namespace containing the problematic custom control from the resource dictionary if you don't need it:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
                    <!-- No GenericResourceDictionary namespace, no compile error -->
</ResourceDictionary>

  • Add the x:Class attribute to the ResourceDictionary element:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:GenericResourceDictionary"
                    x:Class="Whatever"> <!-- This attribute fixes the build -->
</ResourceDictionary>

In spite of these known workarounds I decided to report the issue to Microsoft Connect. I don't want other developers wasting their time on this strange compiler error, like we did. Feel free to upvote it, if your opinion is the same.

Sunday, February 22, 2015 6:35:06 AM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | WPF
My Book

NuGet 2 Essentials

About Me
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

All Content © 2015, Damir Arh, M. Sc. Send mail to the author(s) - Privacy Policy - Sign In
Based on DasBlog theme 'Business' created by Christoph De Baene (delarou)
Social Network Icon Pack by Komodo Media, Rogie King is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.