Our finished chore board

Analogue Trello using dry erase magnetic labels

My wife and I are terrible at chores. We are terrible at planning for them, balancing them (with other tasks and each other), and performing them. We have been terrible for a long time and we have finally accepted it. To mitigate our ineffectiveness, we tried Trello, but all that did was create a new chore, Check Trello, that we promptly forgot to do.

What we wanted was an analogue approach to Trello that would sit on our wall and scream "Do your chores!" at us in a way that we could not ignore. So Chrissy drew up a simple chart on a dry erase board in our kitchen using a list of chores we had created together. This was great. We were finally remembering to get things done, but it was not perfect. We often needed to rearrange chores to adjust for various scheduling conflicts, but erasing them just to rewrite them elsewhere on the board was tedious. Especially so if it meant reorganizing other chores to make things fit.

Our implementation of Trello was flawed.

As a fix for this organisational deficiency, the blank equivalent of poetry fridge magnets came to mind. Dry erase magnets that could be edited and rearranged with ease. I found some ready made solutions on the Internet, but I was not sure that they would fit exactly what we needed, so I went hunting around the local office supply stores. Eventually, thanks to the helpful manager of our local OfficeMax, I came up with a plan to make my own using business card sized magnets and some dry erase tape.

Equipment for creating analogue Trello
Equipment for creating analogue Trello

To make them, I carefully peeled the backing from the business card magnets a little to reveal the adhesive. I then peeled the backing off the dry erase tape a little and lined up the tape with the card, adhesive to adhesive. I then applied the tape to the cards, carefully avoiding any bubbles (usually) and trimming the tape to size.

A business card magnet with backing
A business card magnet with backing
The backing partly peeled back from the magnet
The magnet backing partly peeled back to reveal the adhesive
Applying the dry erase tape
Applying the dry erase tape
A magnet with dry erase tape applied
A magnet with dry erase tape applied

Once I had applied the tape to all of the magnets, Chrissy divided them up into a range of sizes1.

The finished dry erase magnets
The finished dry erase magnets

Then, with all the magnets backed by dry erase tape and cut to the sizes we wanted, Chrissy set up our new chore board.

Our finished chore board
Our finished chore board

  1. We had tried to trim some of the magnets to useful sizes and to remove any exposed adhesive, but we never found a way to do this well 

map

Resolving XML references from embedded resources

Recently, I wanted to validate some XML via an XSD schema. Due to some product constraints and intentions regarding versioning, the schema is an embedded resource and is referenced via the noNamespaceSchemaLocation attribute.

When loading XML in .NET, you can specify an XmlResolver via the XmlReaderSettings . As stated in MSDN, the default uses a new XmlUrlResolver without credentials. This works great when the file is local on disk, but not when it is squirreled away inside my resources.

What I needed was a special version of XmlResolver that understood how to find my embedded schemas. So I created a derivation, XmlEmbeddedResourceResolver, to do just that.

When asked to find a file-based reference, this steps in and looks in embedded resources first for a file of the same name. Since the file could be namespaced anywhere in the resources, I opted to look for any resource in any namespace with the same file name. If it is there, it loads it, otherwise it defers to the base implementation. This means there is no easy way to override the embedded file with a local one; however, that could be redressed by calling the base implementation first and then only searching embedded resources if that failed.

Note that I also implemented the async methods. I am certain my implementation is a little naive, but it generally works. Just be careful if you allow this to be used asynchronously as I discovered you can very easily create a deadlock when used in conjunction with locks. This is not necessarily a caveat of my implementation, but of asynchronous programming in general.

Hopefully, others will find this useful. Let me know in the comments if you use this or something similar.

Unsplash | Free Stock Photos

Unsplash: Completely free images for whatever you want

I recently made the decision to have a featured image for each of my blog entries. The intention was to make things more consistent and easier on the eye. Sometimes, the image to use was immediately obvious and I would get it from my personal photos, at other times, it was not so easy.

Thankfully, my good friend and exceptional designer, Terrance Robb came to the rescue by introducing me to Unsplash. Unsplash is a service that posts ten stock images every ten days. These are high resolution images licensed under Creative Commons Zero, and as such, are completely free to use as you see fit.

Unsplash | Free Stock Photos

Why use Unsplash? Well, when someone puts professional, copyrighted images on the Internet without the permission of the owner, it directly impacts that owner's ability to make money from that work.  I like Unsplash because it encourages people to do the right thing with regards to copyright. Rather than resort to stealing copyrighted images with a right-click, Save As…1, Unsplash provides a free source of images for those who cannot afford professional alternatives. Not only that, but the licensing terms are completely unambiguous. There is no hunting for the appropriate attribution information or license information, you know exactly what your getting with these images.

So, next time you need inspiration or want an image for your presentation or blog and don't have the budget to pay for a professional stock (or custom) photo, don't steal; check out Unsplash.


  1. come on, you know you have done it 

tools

Caching with LINQPad.Extensions.Cache

One of the tools that I absolutely adore during my day-to-day development is LINQPad . If you are not familiar with this tool and you are a .NET developer, you should go to www.linqpad.net right now and install it. The basic version is free and feature-packed, though I recommend upgrading to the professional version. Not only is it inexpensive, but it also adds some great features like Intellisense1 and Nuget package support.

I generally use LINQPad as a simple coding environment for poking around my data sources, crafting quick coding experiments, and debugging. Because LINQPad does not have the overhead of a solution or project, like a development-oriented tool such as Visual Studio, it is easy to get stuck into a task. I no longer write throwaway console or WinForms apps; instead I just throw together a quick LinqPad query. I could continue on the virtues of this tool2, but I would like to touch on one of its utility features.

As part of LINQPad , you get some useful methods and types for extending LINQPad , dumping information to LINQPad's output window, and more. Two of these methods are  LINQPad.Extensions.Cache and Utils.Cache. Using either  Cache method, you can execute some code and cache the result locally, then use the cached value for all subsequent runs of that query. This is incredibly useful for caching the results of an expensive database query or computationally-intensive calculation. To cache an IEnumerable<T>  or IObservable<T>  you can do something like this:

Or, since it's an extension method,

For other types, Util.Cache  will cache the result of an expression.

The first time I run my LINQPad code, my lazily evaluated query or the expression is executed by the Cache method and the result is cached. From then on, each subsequent run of the code uses the cached value. Both  Cache methods also take an optional name for the cached item, in case you want to differentiate items that might otherwise be indistinguishable (such as caching a loop computation).

This is, as I alluded earlier, one of many utilities provided within LINQPad that make it a joy to use. What tools do you find invaluable? Do you already use LINQPad ? What makes it a must have tool for you? I would love to hear your responses in the comments.

Updated to correct casing of LINQPad, draw attention to Cache being an extension method for some uses, and adding note of Util.Cache3.


  1. including for imported data types from your data sources 

  2. such as its support for F#, C#, SQL, etc. or its built-in IL disassembly 

  3. because, apparently, I am not observant to this stuff the first time around. SMH 

brick-wall

Corporate Dogma: Good Intentions, Bad Policies

Recently, a colleague wanted to update our corporate profile on a well-known website for sharing interview experiences; we will call them Brickwindow. When signing up for a free corporate account, he filled out the fields honestly, stating his name, his job title, and checking the box that stated he represented HR, which he does as part of his various duties. 24 hours later (or thereabouts), the response came back saying that Brickwindow were not permitting him to open the account as his job title wasn't HR-related. They would need a C-level employee or member of the HR department to verify his authority (or to open the account themselves).

Here's the issue. Our organization does not have an HR department or traditional C-level employees like CEO, CFO or CTO. Just as we are trusted to make good software engineering decisions, we are trusted to make good decisions in other aspects of the business, including who we hire. There are no managers, no Chief Gubbins Officers, and no HR departments. So, my colleague wrote back to Brickwindow outlining how our company structure just does not fit their rules. He assured them that he is authorized to make HR decisions. Shortly thereafter, they responded reiterating that he could not have the account and asserting that they are committed to the security of their users.

So, I signed up.

I have the same job title as my colleague, but since we can choose our own job titles, I temporarily promoted myself to Assistant to the Director of HR. After submitting my application, I pondered on how they might verify this and quickly updated my LinkedIn profile to state the same title1. About thirty minutes later I had an account. It was that easy. My colleague had just been too honest. As for the commitment to user security, Brickwindow sent me my new user name and password in plain text. Brilliant2. I quickly changed it and then forwarded the account details to my colleague so he could continue with the task he had attempted to do the day before.

I think this tale serves as a great example of how we can get bogged down in process and miss the purpose of an activity altogether. In trying to make sure that no one could just create an account for any old company, Brickwindow made assumptions about its corporate user base that meant they could not adapt when faced with something that did not conform. Not only that, but they were so busy trying to enforce those assumptions, they missed the glaring loopholes. All they managed to achieve was a huge waste of time; theirs and ours. This had been an opportunity for Brickwindow to demonstrate they are forward thinking and adaptable, but instead they made it clear they are stuck in the past with the monolithic corporate structures of C-level employees and middle management. In the end, they failed on three major points: identity, roles, and security. We only persevered because we appreciate the primary service provided by Brickwindow.

So, next time you are faced with a situation that does not fit the script, consider whether the script needs to change before trying to change the situation. These conflicts are an opportunity to impress, not stick to rigid rules that don't even achieve the goals they intend to.

If you have any similar tales of well-intentioned processes gone wrong, or corporate dogma that gets in the way, please post them in the comments.

As for me, I have since demoted myself back to a Senior UX Engineer (a title I had chosen when I found out I would be speaking at CodeMash 2.0.1.4). It turns out HR was just not a good fit for me.


  1. Apologies to anyone who was confused 

  2. sarcasm 

but mostly…