Close

What to Log in .NET

In my previous post, I discussed a lot of the when of logging – when to log things in your application. So in this post I’d like to talk a little bit about what to log.

Having lots of logs is certainly better than having none, but if the logs don’t capture important information that allow you to make decisions about your application design, then they are not as valuable as they could be. So in this post I will discuss certain key pieces of information which can greatly enrich your logs:

Web Request Data

In a web application, it can be hugely useful to log certain information about the incoming request. The first things we want to take a look at are what was requested. See below for WebForms/MVC code snippets:

Protocol

If your web server serves both HTTP and HTTPS requests, you should log the protocol being used for the request. (You do use HTTPS, right?)

Hostname

By logging the hostname, we can see the actual domain that was requested, including ports (if the port was specified) and the subdomain.

Path

This represents the actual request path – the part after the hostname and before the query string. In MVC apps, this is used for routing to the appropriate controller/view, and in WebForms apps this will be the path to the .aspx page which is rendered.

Query String

Because query strings are used for passing in important information, the request information is not really completed without it. NOTE: if you are passing sensitive data via query strings, be sure not to log them! Additionally, see this StackExchange post for reasons why you should not do this.

IP Address

This one is a common pitfall, but it’s good information to have no matter what. Remember that the IP address is the request of the machine which sent the request to you, and not unique to a user. For instance, if multiple people in the same home visit your website on different computers, you will most likely see the same IP address for all of them.

To add to the complexity, if a proxy, CDN, or load balancer forwarded the request to you on behalf of a user, then this IP address may not be the user’s at all. But take heart: well-behaved proxies will usually include the original IP in a header which you can retrieve. A common way of doing this is with the X-Forwarded-For header. Some other services such as Cloudflare and Akamai instead use the True-Client-IP header. Depending on your network infrastructure will determine where the actual user’s IP address will be stored in the request.

User Agent

The User Agent is another important header to capture – it indicates the web browser and operating system that the user is using. This can be very useful when attempting to diagnose bugs that only occur on certain browsers, and can also give insight into the technologies in use by your users. At work we were shocked to find that an extremely small percentage of our users were viewing our website on Android TVs!

Code Example: WebForms and .NET Framework MVC

Below is an example of how to fetch all of these values in an MVC or WebForms app. In your Controller/Page, there is a Request property defined which contains lots of information about the request:

var hostname = Request.UserHostName;
var path = Request.Path;
var queryString = Request.QueryString;
var ip = Request.UserHostAddress;
var forwardedFor = Request.Headers["X-Forwarded-For"];
var trueClientIp = Request.Headers["True-Client-IP"];
var userAgent = Request.UserAgent;

Code Example: .NET Core MVC

The implementation of the MVC Controller’s Request property’s class is a little different in .NET Core, but the same principles still apply here:

var hostname = Request.Host;
var path = Request.Path;
var queryString = Request.QueryString;
var ip = Request.HttpContext.Connection.RemoteIpAddress;
var forwardedFor = Request.Headers["X-Forwarded-For"];
var trueClientIp = Request.Headers["True-Client-IP"];
var userAgent = Request.Headers["User-Agent"];

Code Example: ASP.NET Core Owin

If you need to retrieve the request data from the Owin context during the execution of your Owin pipeline (this is a great place for performance and error logging!) then it is very similar to the above example, except that we will get the request object from the Owin context instead of a property on our Controller:

app.Use(async (context, next) =>
{
  var hostname = context.Request.Host;
  var path = context.Request.Path;
  var queryString = context.Request.QueryString;
  var ip = context.Request.HttpContext.Connection.RemoteIpAddress;
  var forwardedFor = context.Request.Headers["X-Forwarded-For"];
  var trueClientIp = context.Request.Headers["True-Client-IP"];
  var userAgent = context.Request.Headers["User-Agent"];
  return await next();
}

User Data

It is very useful to have information about the user themselves when looking at logs. This lets you know who caused the log, but can also be a useful aid when troubleshooting bugs, since you can create a test account with similar data. It is also very useful for audit logging, if you need to answer a question about which user took an action and when.

To get data about the current user, you will need access to the user’s Principal. How you get access to this will vary by environment:

  • In WebForms or .NET Framework MVC apps, the Page/Controller has a User property which will contain the current user’s Principal.
  • In most .NET Framework apps, you can also access the current user’s Principal using Thread.CurrentPrincipal.
  • In .NET Core apps, Thread.Current principal is not available, and you should instead use .NET Core’s dependency injection and the IHttpContextAccessor interface.
  • In the Owin pipeline, you can access the User property of the HttpContext, which contains a ClaimsPrincipal.

Once you have access to the user’s principal, you can use it to check whether they are properly authenticated, and get their name:

var userPrincipal = Thread.CurrentPrincipal;
var isAuthenticated = userPrincipal.Identity.IsAuthenticated;
var userName = userPrincipal.Identity.Name;

Additionally, a very common implementation of the IPrincipal interface is the ClaimsPrincipal, which can contain all sorts of information about the current user – common and useful claims to look at are the user’s roles, email, and any application-specific claims you might generate during user login, such as a user ID or customer ID.

Caller Data

A very useful diagnostic tool that I’ve come to love is: including the file and method which actually wrote the log. While you can rely on stack traces in the case of exception logging, it can also be useful to find out where other types of logs, such as user behavior logs are being generated, in order to put them into context.

C# exposes a couple of really handy attributes for this purpose which can be applied to your method parameters. The first is the CallerMemberNameAttribute which contains the method name of the method which called yours. The second is the CallerFilePathAttribute, which contains the path on disk to the source file in which the calling class is defined (note that the path will usually correspond to the machine which compiled the code and not necessarily the one on which it is running!)

To use these attributes, you simply need to add them to nullable string parameters on your method which does the logging:

private void CallerExample([CallerMemberName] string memberName = null,
    [CallerFilePath] string filePath = null)
{
  var fileName = filePath.Substring(filePath.LastIndexOf(Path.DirectorySeparatorChar) + 1);
}

Bear in mind that the values at runtime will be the calling method – even if you use some private helper methods to do logging, in which case the method and file name may always point to your logging class. In this case, simply add the parameters with the Caller attributes to your public method and pass the values in to your private method – the values you pass in as arguments will be used instead of the actual caller values.

Environment Data

Capturing information about the environment your code is running in can be very useful when diagnosing environmental issues, such as when an error only occurs on one server for some reason.

Some of the most useful pieces of information here are:

  • Machine Name (useful to know if something is only happening on one machine.)
  • Thread ID (useful for diagnosing race conditions.)
  • UserAccount under which the application is running (useful for diagnosing permissions issues.)

These values can be accessed on the Environment static class:

var machineName = Environment.MachineName;
var threadId = Environment.CurrentManagedThreadId;
var userAccount = Environment.UserName;

Error Data

This one is fairly easy, but is nonetheless very important. Whenever your application detects an error or exception, you should log the Exception message and stack trace for diagnostics.

Many programmers simply log the exception itself and think that they’re done, but remember – your exception logs will be the first place you look when diagnosing a bug! Think ahead and put yourself in your shoes and consider what additional information might help you get to the bottom of a tricky bug, and log it now! Good candidates for this are things like method parameters, collection sizes, or user roles if an authorization exception is possible.

Conclusion

I hope that this has given you some useful ideas and code examples to really up your logging game. As you enrich your logging story by adding additional data to logs, and a more thorough system of logging to your application, you will find yourself learning about all sorts of things that happen during your program’s execution that you may never have discovered through normal testing.

Techniques and Advice for Logging in .NET

When setting out to design maintainable software, one of the most critical things to bear in mind is creating feedback loops that allow you to make code decisions based on the application’s actual use and performance under real-world circumstances. A crucial aspect of this is that your application needs to be able to tell you when something is wrong.

One of the main ways to achieve this is by application logging. There are many forms of logging, but in the scope of this article we will discuss a few categories of logging:

Diagnostic Logging

Diagnostic logging is, broadly logs that help you identify and troubleshoot failure scenarios in your application. Below we will discuss a variety of ways to employ diagnostic logging to help reduce your time spent tracking down tricky bugs to help you spend more time on the fun parts of programming.

Catchall Exception Logging

This is the most basic form of exception logging, but its great benefit is that if any code is written in your application that does not correctly handle exceptions, you are guaranteed to have a log about it! Depending on the structure of your application this may take many forms.

In ASP.NET applications, you can define a method in your Global.asax file to handle all errors that occur during processing of an HTTP request:

void Application_Error(object sender, EventArgs e)

In an application using the Owin pipeline, you can write a simple middleware which wraps all subsequent middleware executions in a try/catch, something like this:

app.Use((context, next) =>
{
  try
  {
    return next();
  }catch(Exception ex)
  {
    // Log the exception here.
  }
}

In .NET desktop applications, you can use the AppDomain class’ UnhandledException and FirstChanceException lifecycle events to log either all exceptions or only unhandled exceptions, whichever you prefer (note that in recent versions of .NET Core console apps this works as well!):

AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
{
  var ex = args.ExceptionObject;
  // TODO: test the exception object type and log it
};

Downstream Dependency Error Logging

Any time your application interacts with a downstream dependency, such as a database or another API, you should wrap the interaction in a try/catch and log any exceptions that get thrown. This is incredibly useful for determining when failures in your application are caused by bugs or outages in other people’s code!

try
{
  myDownstreamDependency.SendRequest()
}catch(Exception ex)
{
  // Log the exception here.
}

Note that when doing this, you should also include as many specifics about what you were doing in your log. Things like: which API call you were making, what URL you were accessing, what arguments you passed in, which user was taking the action, etc.

Soft Failure Logging

As we are adding logging to our application, it is important to remember that not all failures in our code result in exceptions being thrown. There are other code failures which can result in bad/missing data without ever throwing an exception. One good example of this is when you know an operation should always return a non-empty list, but the resulting list is empty. While this may not cause an exception that causes your application to be unusable, it is still a logical error which will have some known or unknown impact on your users and should be logged.

Performance Logging

Another thing we want to know about in our application is when something causes it to run slowly. In many cases, problems or changes in our code can cause the code to begin running more slowly, which from the user’s perspective is a bug!

So any operation which a user initiates which could cause a bad user experience if it were to take too long should be wrapped in some form of performance logging. A great tool for this is the .NET Stopwatch class.

var stopwatch = new Stopwatch();
stopwatch.Start();
// Do something
stopwatch.Stop();

After calling the Stop method on our Stopwatch, then we can check its ElapsedMilliseconds or ElapsedTicks properties to check how much time has passed, and include this information in our logs.

HTTP Request Performance Logging

Logging the performance of all HTTP Requests is a great way to get a high-level overview of the performance of a web application. Depending on your architecture there are a few ways of doing this, but in ASP.NET applications with a Global.asax file, you can define methods to handle the ASP.NET lifecycle events for the beginning and end of handling a request:

private Stopwatch _stopwatch;
protected void Application_BeginRequest()
{
  _stopwatch = new Stopwatch();
  _stopwatch.Start();
}
protected void Application_EndRequest()
{
  _stopwatch.Stop();
  // TODO: log the performance here
}

In an Owin application (such as ASP.NET Core apps), it’s even easier, you can just define a middleware near the beginning of your Owin pipeline that calls the rest of your middleware, and log the performance there:

app.Use((context, next) =>
{
  var stopwatch = new Stopwatch();
  stopwatch.Start();
  var result = next(); // We run all of our other middleware
  stopwatch.Stop();
  // Log the performance here.
  return result;
}

Downstream Dependency Performance Logging

Once again it is very important to keep track of your downstream dependencies. Not all problems in your application originate in your code, so being able to tell when slowness in your application originates in an API or database you depend on is very important to point your troubleshooting in the right direction (and point blame in the right direction, if you have the misfortune to work for an organization which does not have blameless postmortems…)

As with our downstream dependency error logging, we should capture as many specifics as possible about our API call/DB query in order to facilitate rapid troubleshooting of the problem.

User Behavior Logging

It can be very useful to know how your users are actually using your application. The scope of this extends beyond just troubleshooting bugs and problems, to informing your technical priorities and even feature grooming. Below are some suggestions about useful types of user actions to log:

Log In/Out

Whenever a user begins or ends using your application, you should log that behavior. This provides very insightful usage statistics. Additionally, when a user attempts to log in, you should record whether their login attempt succeeded or failed – this is useful for detecting brute force and DDoS attacks, or even informing your product decisions around things like password recovery or failed password lockout thresholds/durations.

New Features

When you release a new feature, it can be very useful to log how many users are using the feature and how they are using it. This is important feedback for an Agile development process – you can’t always talk to your users about how they are using your application, but you can log what they do! Combining this with error and performance logs can give you a lot of insight into whether users are having a positive experience with a new feature.

High-Impact Features

If a particular feature in your application is known to have a significant performance impact, it can be very good to log the frequency with which users use that feature. This might be operations such as provisioning a new virtual machine, or clearing all of the cached data for their customer.

Code Behavior Logging

Just as User Behavior Logging is useful for finding out what your users are doing, Code Behavior Logging is useful for finding out what your code is doing.

Application Lifecycle

Logging key events in your application lifecycle can be really useful for diagnosing startup problems and crashes. In particular, one of the first things you do when your app starts is create a log with the current machine name! This not only gives you a history of when your app was started or restarted, but also lets you make sure that your logging is working!

In a .NET Core application, the easiest place to do this is right in the beginning of the Main method:

public static void Main(string[] args)
{
  // Write your log here!
  CreateWebHostBuilder(args).Build().Run();
}

For older .NET Framework WebApps (MVC/WebForms), you will instead need to do this during the Application_Start HttpApplication lifecycle event in your Global.asax file:

protected void Application_Start()
{
  // Write your log here!
  // Usually startup things like dependency injection etc. go here.
}

 

For WPF desktop applications, the App.xaml.cs constructor or the MainWindow’s constructor are good places.

Other useful lifecycle events to capture are: application shutdown, and the execution of any recurring background worker threads which may run in the background during normal operations.

Branch Execution

This is particularly useful in legacy codebases. Sometimes you will find yourself staring at some old code and wondering “does this code even ever get hit any more?” Branch execution logs can answer this question for you – simply add a log statement in that code branch and release it to users. It won’t take long before you’ll have an answer to that question.

Data Logging

When it is not clear what the actual data in your application looks like at runtime, it can be useful to log the data itself or key attributes about it. For instance, if you are doing lots of string operations in your application, it might be useful to log the length of those strings so that you know how important optimizing your string operations is. If the strings are always small, the optimization work may not be valuable enough to do. But for long strings it might warrant a higher priority.

Audit Logging

Audit Logging is designed to give you a record of sensitive user behaviors. There are many concerns involved in audit logging – audit logs are often customer-facing and can sometimes play a role in compliance and legal matters. So it’s really important to get these ones right.

User-Facing Data Changes

Any time a user modifies data that users have access to, and that change is persisted anywhere (such as a database or filesystem) you should generate an audit log for this behavior. Be sure to log not only the data that was modified, but the user doing it, and if possible, some details about what was changed.

Viewing Sensitive Data

While we are normally worried about auditing when users change data, some data is so sensitive that even viewing it warrants an audit log entry. What data falls into this category will vary depending on your application, but good candidates are financial information, or when one user views personal data about other users.

Conclusion

I hope that this blog has given you some good heuristics to think about when adding logging to your application. Logs are an absolutely amazing tool when it comes time to troubleshoot a bug, diagnose an outage, or provide customers with really specific and useful data about a data loss scenario. When things go wrong (and they will) logs are what helps you put on your Sherlock Holmes hat and make sure it doesn’t go wrong twice!

The Four Phases of Dance DJs

In my experience, as DJs gain more experience, they go through several phases. I’d like to discuss them today, to help my friends who are just starting out DJing dances think about how to level up their DJ game as quickly as possible:

Phase 1: The “Music I Like” DJ

This is where most DJs begin their journey: they have created a nice little collection of music they love to dance to, and they create playlists from that. It’s all of their favorite songs, and they’re able to put together 1-3 hours sets containing only songs they enjoy.

This is a great start, and the community can always use eager people willing to volunteer their time to DJ for us! But the fundamental problem with this style of DJing is that it fails to account for other people’s tastes. By creating playlists that appeal perfectly to one person’s preferences, you may accidentally also be creating playlists that don’t appeal at all to other dancers who come to your dance!

Eventually most DJs notice this and begin to move into Phase 2.

Phase 2: The “Music the Dancers Like” DJ

These DJs have expanded their collection to include the most popular songs for their dance style – even the ones they personally don’t like. Their playlists still contain some of their absolute favorites and some guilty pleasures, of course – but the majority of their set is designed to appeal to their audience rather than their personal tastes.

This is a huge improvement from the first phase of DJ’ing because by taking other people’s tastes into account, you will rarely have your dancers going home thinking “man, that DJ didn’t play a song I liked all night!” But DJs in this phase often give little thought to the progression of their music throughout the night – whether their transitions between songs makes sense, and whether they are playing so many similar songs in a row that their dancers who would prefer something different are getting bored.

As DJs endeavor to bump their game up to the next level, they move on to Phase 3.

Phase 3: The “Perfect Playlist” DJ

These DJs invest a lot of time, love, and energy into their playlists. They pick the first song carefully, making sure that their first song is a popular one that kicks off their set with a bang and gets everyone on the floor. They pay close attention to transitions between songs, making sure not to have too many songs of the same tempo/style in a row, to give their dancers a breather between fast songs, and making sure that the vibe doesn’t become sleepy with too many slow songs in a row.

chrome_2019-01-13_23-35-32.jpg

They also make sure that their dancers with particular tastes don’t have to go too long between songs that they really love – trying to mix in various styles at regular intervals. This gives their dancers a nice rhythm for the evening, taking social breaks on the songs they like less, but knowing it will only be 5-10 minutes until a song they will love is played. Everyone needs to take breaks sometimes, that’s expected. But we’ve all had the disappointing experience of going 15-20 minutes without hearing a song that really makes us want to jump up and dance.

But crowds change, tastes change, popular songs become played out, and we all know that the difference in vibe between late night dancing and early evening dancing is like night and day. So a great playlist, while it is a great start, still isn’t the top tier of DJing.

Phase 4: The “Handcrafted Playlist” DJ

These DJs create a playlist as a starting point, but know the old saying that “no playlist ever survives contact with the dancers.”

The Shire and everything after: Warband goes live!

Because every crowd, every event, every evening is different, these DJs update their playlists on the fly based on who showed up and what the energy level of the room is like. If they see a large group of people sitting down for a while, they keep changing songs until they manage to play something that gets them on the floor. As they do this, they learn the tastes of the various cliques of dancers while still feeling out and shaping the vibe of the evening. As the evening gets late, they play more slower songs, but also know that songs with a slow tempo (BPM) can nonetheless have very high energy.

They also know their community and play songs appropriate for the hour. We all know that as the evening goes on, the dance (and the crowd of dancers) evolves in predictable ways. Many West Coast Swing events accommodate junior dancers – this is great, but it means that songs with profane lyrics are better played at 2am than at 10pm. Likewise, they know that their older dancers will love to hear hit songs from decades past, and will plan to play those earlier in the evening when the crowd will best enjoy it.

Conclusion

As I’ve worked on my own DJing, I’ve managed to journey through the first 3 phases of DJing, and am now challenging myself to become a true Phase 4 DJ. If you are a DJ or an aspiring DJ, I hope that this article gives you some things to think about to find ways to up your own DJ game!

There’s nothing better than playing music for an energetic crowd all night, and then having people with varying tastes in music come up to you afterward and tell you they loved your set – that’s how we know we’ve really done our job well and created something special!

How to Set Up a Unity Editor Test Project

If you’re like me, you like to be able to write unit tests for logic in your code. Unfortunately, Unity has historically not had great support for unit testing in the form that most programmers are used to – however recently, they are adding more and more support tor automated test.

Tonight I spent a fair bit of time figuring out how to write simple NUnit tests for my code in Unity, and now that I’ve figured it out, I wanted to share my findings!

Step 1: Create a Test Assembly

First, in your Scripts folder, right-click and add a Tests Assembly Folder:

Unity_2018-12-04_23-00-19.png

You can name it anything you like. Under the covers, Unity manages C# projects for you, rather than using traditional .csproj files that most .NET developers are used to. These assemblies are managed using Assembly Definition (.asmdef) files – when we created our Tests Assembly Folder, Unity created an assembly definition for us.

Step 2: Configure our test assembly for Editor mode

Let’s navigate to the new folder and check out the assembly definition by clicking on it:

Unity_2018-12-04_23-06-16.png

Now what we want to do is configure this assembly to use the Editor platform. For programmers used to old fashioned coded unit tests, this will be the most similar to what you’re used to. The other platforms allow you to design Play Mode tests which won’t be covered here. To change this, we can just select the Editor platform, then hit Apply:

Unity_2018-12-04_23-07-58.png

Step 3: Create your test script

In the new Test folder, right-click and create a new C# Test Script:

Unity_2018-12-04_23-09-08.png

This will create a test script for you with a couple of test methods using Unity’s UnityEngine.TestTools assembly, which is based on NUnit.

Step 4: Run our tests

Open the Test Runner (Window > General > Test Runner) and then select EditMode. here we will see the DLL generated from our Test Assembly definition, along with the tests inside of it:

2018-12-04_23-12-11.png

Simply right-click and Run anywhere in the assembly hierarchy to run the tests:

2018-12-04_23-12-53.png

Step 5: Create an Assembly Definition for your regular game code

Okay, so now we have tests, and we can run them. Awesome! But there’s a big gotcha – our test assembly is generated by Unity dynamically, meaning we can’t add an assembly reference to our code! If we try, then we will just get console errors when we try to run them in the Test Runner saying that our namespaces are not found.

To get around this, we can create another Assembly Definition for our main game code, then reference it in our test Assembly Definition. Let’s do this in our Scripts folder:

2018-12-04_23-15-58.png

We can name this anything we want. Once we do this, if you reload your solution in Visual Studio, you will notice that your Assembly-CSharp project has been renamed to match our new Assembly Definition:

devenv_2018-12-04_23-16-53.png

Before…

devenv_2018-12-04_23-17-59.png

After.

Step 6: Reference our main game code Assembly from the test Assembly

Now let’s go back to our test assembly definition, and add a reference to it:

2018-12-04_23-19-23.png

Select your Assembly from the list, then click Apply.

Step 7: reference your game code in your tests!

Now the test Assembly generated by Unity will have a reference to the Assembly containing our main game code. So now we can simply reference our code normally. To demonstrate this, we can define a really simple class in our game code assembly:

devenv_2018-12-04_23-20-42.png

Then let’s go and edit our test to reference it:

devenv_2018-12-04_23-24-13.png

Once we add a using statement to import our namespace, we can reference our game code directly in tests. Now simply run your test again in the unity Test Runner!

Next Steps:

Now that we have some unit tests in Unity, there’s a few new things to know. First, when the Test Runner builds your solution in the background, it will not display errors directly in the Test Runner. You’ll have to look for these errors in the Unity Console:

Unity_2018-12-04_23-26-45.png

Second, it can often be useful to debug through our test code while it’s running – to do so, simply attach to Unity, then run your test(s) via the Unity Test Runner, and you will be able to hit breakpoints and step through your code.

2018-12-04_23-28-18.png

And that’s it! For those of you like me who have a background in using coded tests to make sure your code keeps working long after it’s written, I hope this helps you adapt your testing habits to the Unity world! Happy coding!

Newcomer’s Guide to West Coast Swing Competition Points

When I was a new dancer, I found the WCS points and scoring system to be pretty opaque and hard to understand:

chrome_2018-12-10_20-44-27.png

Yep, all those numbers totally make sense

Lately I’ve been thinking about scoring in the WCS community a lot. I’ve had some friends, both new and experienced in the community express confusion at the scoring systems in conversation with me. And I’ve also recently started working on an open-source project to create a free code implementation of the WSDC Relative Placement Scoring System.

As a result, I’ve come to appreciate the way that the judging and points system shapes our community, and think that it is a pretty good solution to the insanely difficult problem of turning subjective opinions of dancing into skill levels and numeric contest results that make sense from event to event.

So, without further ado, here is everything you need to know about scoring in West Coast Swing!

What Are Points?

The World Swing Dance Council (WSDC) uses points as a guideline for event directors to place competitiors according to their skill level. Each skill level defined by the WSDC has certain point requirements for its participants. The full details are explained in their Points Registry Document, but I will summarize the highlights here:

Skill Level Description
Newcomer Beginner, must have earned no points. You may skip ahead to Novice if you prefer.
Novice Competitors must compete in Novice until they earn 16 Novice points. At 30 points, you must begin competing in Intermediate.
Intermediate May move to Advanced with 30 Intermediate points.
Must move to Advanced with 45 Intermediate points.
Advanced May move to All Star with 45 Advanced points in the last 36 months.
Must move to All Star with 60 points in the last 36 months.
All Star Must have either 45 Advanced points in the last 36 months, or 3 All Star points in the last 36 months.
Champion/Invitational/Pro Determined by the event director.

In addition, the WSDC defines two additional competition categories which are defined by age. Juniors is for competitiors under 18 years old, while Masters is for competitiors over 50.

How Do I Know How Many Points I Have?

You can search for your own point total (or any of your friends/role models!) by name in the World Swing Dance Council Points Registry.

It can be pretty neat to look at someone’s points after they have competed for a while, it tells part of the story of their career and experiences in the WCS world!

How Many Points Do I Get For Competing?

WSDC points are awarded based on both your placement in the competition, as well as the number of competitors in your skill level/role. Larger events award more points for the same placement, since there are more competitors. The WSDC defines six tiers of competition:

Tier # of Competitors 1st Place 2nd Place 3rd Place 4th Place 5th Place Additional Placements
Tier 1 5-10 3 2 1 0 0 0
Tier 2 11-19 6 4 3 2 1 0
Tier 3 20-39 10 8 6 4 2 1pt (up to 12th Place)
Tier 4 40-79 15 12 10 8 6 1pt (up to 15th Place)
Tier 5 80-129 20 16 14 12 10 2pt (up to 12th Place)
Tier 6 130+ 25 22 18 15 12 2pt (up to 12th Place)

Note that the same skill level competition may be in two different tiers for leaders and follows. For instance, if a competition has 39 leaders, and 40 follows, it will award points according to the tier 3 rules for leaders, but follows will get points according to the tier 4 rules, even though they compete and are judged as a couple in finals.

How Do I Get To Finals?

This differs a bit from event to event, and is influenced to some extent by the head judge’s preferences. But the general rule for prelims and semi-finals is that the judges are asked to award each competitor individually (not couple!) a Yes, No, or Maybe/Alternate vote. The number of “Yes” votes each judge can award is usually equal to the number of competitiors which will be in the next round of the competition. For example, if the judges are judging prelims, and semi-finals will have 30 couples, each judge may award 30 “Yes” votes, and then select 3 alternates.

The competitiors with the most Yes/Alternate votes progress to the next round.

I Made Finals! Now What?

Congratulations! When looking at the final results, it can be pretty confusing your first time when one judge places you first, and another places you 10th. How do they figure out which place you actually get? This is where the Relative Placement Scoring System comes in!

The Relative Placement Scoring System is described by the WSDC in a very detailed document you can read here.

In short, an odd number of judges rank every couple in the finals from first place to last. Having an odd number of judges is important, because placements are awarded based on having a majority of judges scoring you at or above a particular placement. Then, once all of the judges’ scores are tallied, the final placements are awarded in rounds.

  • First, each competitor’s 1st place scores are added up, and if any couple has a majority, they are awarded first place.
  • If no couple had a majority of judges who placed them 1st, then we look at every couple’s 1st and 2nd placements. If a couple has a majority, then they are awarded first.
  • This repeats for 1st through 3rd, 1st through 4th, and so on until all placements are awarded.
  • In the event of a tie in a particular round, there are several ways of resolving the tie:
  • If a couple has a larger majority of judges who placed them at or better than the current round, they win. For example, if there are 7 judges, 4 are needed for a majority. If one couple has 5 placements in the current round, and another has only 4, the first couple recieves the best available final placement, and the second couple is placed just behind them.
  • If a couple have an identical majority, (4 and 4, for example) then the numerical values of their placements are compared. Let’s consider two couples who both have four judges who awarded them 1st-2nd place. If one couple has three first places and a second (1+1+1+2=5), while the other couple had two second places and two first places(1+1+2+2=6), the first couple would win because the sum of their 1st and 2nd places was lower.
  • There are several more methods of breaking ties, but the two listed above resolve the vast majority of ties in any given round. If you’re interested to know more, you can read the document linked above for all of the gory details!

Once you have your final placement, then you may be awarded points, according to the tier of your event.

The Head Judge Gave Me a Good Placement, But I Didn’t Finish Well. What Happened?

In the WSDC Relative Placement Scoring System, the head judge’s scores are only used when another judge’s scores cannot be used. For example if a judge accidentally awards two couples first place, or if they feel ill during judging and are unable to finish, their scores may be discarded and replaced with those of the head judge.

The title “head judge” makes it sound like their scores would carry more weight than the other judges, but in reality, the head judge’s scores are usually not used in determining the final placements at all.

Many events will only publish the placements from judges whose scores were used in the final determination, while others include the head judge’s scores, to allow competitiors to see all of the judges’ opinions on their performance.

Sometimes I See Competitiors Competing in Skill Levels They Don’t Have Points For. What Gives?

The WSDC allows competitiors to petition to dance one level above or below their official level. This is generally left to the discretion of the head judge at the event, but there are many reasons for competitiors to seek to dance in another skill level.

  • An instructor who has never competed in WCS before may not wish to compete against their own students in Novice, which could be demoralizing for the students.
  • An Advanced dancer who has taken a long (several years) break from dancing due to life changes or injury, and wishes to compete at an Intermediate level to get back into the groove of competition.
  • A competitior who competes well at WCS events which are not recognized by the WSDC and don’t award points may feel confident dancing “up” a level in an official WSDC competition based on their past performance.

 

That’s a pretty good rundown of the rules of competition in the WCS world. Let me know in the comments if you have any other questions about WCS points and judging that I haven’t answered, and I’ll add them to this article!

Versioning NPM Packages in TFS

So I recently needed to build an NPM package with TFS, and wanted the version number to be updated automatically on build. But after searching, I couldn’t find a good example of how to do it, and TFS seemed to have no tools built in to help.

So I finally I just wrote a simple Powershell script to handle it, and wanted to reproduce it here for the benefit of others who have the same issue:

cd $env:BUILD_SOURCESDIRECTORY
$a = Get-Content 'package.json' -raw | ConvertFrom-Json
$a.version=$a.version.Substring(0, $a.version.LastIndexOf(\".\")) + \".\" + $env:BUILD_BUILDID
$a | ConvertTo-Json  | set-content 'package.json'

Or, if you use GitVersion like we do, after running the GitVersion build step, you will have new environment variables with version numbers in different formats available, which can be used like so:

cd $env:BUILD_SOURCESDIRECTORY
$a = Get-Content 'package.json' -raw | ConvertFrom-Json
$a.version = $env:GITVERSION_NuGetVersion
$a | ConvertTo-Json  | set-content 'package.json'

Hope this helps anyone trying to build and publish NPM packages as part of a TFS build!

Firefly: Out of Order

Recently, I was attempting to consolidate my media collection onto my home PLEX server (which I really like!) In the process, I attempted to copy over all episodes of Firefly from the series’ Blu-Ray release, and upon doing so, found that they were in a completely incorrect order.

I assumed the mistake was on my end at first, but after doing some research, it seems that the reason for this is that FOX did not originally air the series in the correct order. For example, the 2-hour Pilot episode meant to introduce all of the characters was the 11th episode they aired (which probably has something to do with how such a wonderful show got cancelled, but don’t worry it’s fine I’m not bitter or anything I just think we need some time apart, FOX, I’ll be staying with my parents this weekend, you watch the kids.)

Later, the series was released on disc in the intended order, but this meant that the database used by PLEX to determine the names and order of episodes, TVDB, had to make a decision: which order was right? In this case it seems that they decided to go with FOX’s order, but that isn’t the order I wanted my collection to play in.

So to help out anyone else who encounters this strange discrepancy, below is a table of the episodes, listed in the order they appeared on the Blu-Ray release of the series, with their originally aired order (to which PLEX defaults) noted. Simply add the series to your PLEX server and then create a playlist with the episodes in the right order if you want to watch the whole series all the way through!

Blu-Ray Episode # Title Originally Aired #
1 Serenity (Parts 1 & 2) 11
2 The Train Job 1
3 Bushwhacked 2
4 Shindig 6
5 Safe 7
6 Our Mrs. Reynolds 3
7 Jaynestown 4
8 Out of Gas 5
9 Ariel 8
10 War Stories 9
11 Trash 13
12 The Message 14
13 Heart of Gold 12
14 Objects in Space 10
Back to top