Category Archives: Software Development

The Crotator: A Custom Selection Tool

As a developer, I have tremendous appreciation for usability and respect for those that can conjure it.  Like many developers, though, it’s challenging for me to do on my own.  I’d like to quickly detail the fruits of a small usability example that I came up with recently for a customer’s project.

The Requirements

The customer wanted to take an image and crop out individual pictures within the image. To complicate things, the pictures would not be perpendicular but would need to be cropped and rotated to be straight. The easy thing to do would be to build a rectangular selection tool like you might find in PhotoShop. It would satisfy the requirement of cropping/rotating the pictures, but would require many steps to initiate the initial drag, rotate the whole thing, move it, resize corners, and so on. It was tedious.

What we needed was this:

  • Must crop the image
  • Must rotate the image so it is straight
  • Fast
  • Easy to learn
  • Relatively accurate

A Possible Solution

We talked through a few options, including the previously mentioned PhotoShop style selection tool. Some ideas were good but impractical. Slowly I started to imagine dragging an initial rectangle from corner to corner, and then dragging one of the other corners to the right position with the opposing corner reflecting the movement.

Doesn’t make sense? That was the trouble I had explaining it to others. Ultimately I built the prototype, and once you could actually see what was happening, it made sense.

The Crotator

It sounds like something you need a chiropractor for, but because it both crops and rotates it was named the Crotator. Here is an animation that hopefully makes clear how it works.

In the animation above, the initial selection box is created by dragging from the top left to lower right corner. Once complete, the top right corner of the selection box is dragged to the top right of the image and the bottom left point mirrors the movement to maintain rectangularity.

A Success

The good news is that the Crotator was a success. It fit the requirements and the customer loved the simplicity. In practice, you could show someone once or twice how to use it and they got it. In many cases, you can crop and rotate an image with two drags.

Thankfully the team wasn’t willing to accept the obvious and poor answer to the problem. We were able to focus on finding a great solution to our specific problem that was key to the functionality we were adding.

The Beauty of the Open/Closed Principle

It’s good to be SOLID. Of the principles that make up SOLID, I’ve found the Open/Closed Principle (OCP for short) to be one of the more difficult. There are plenty of explanations around the web, but while identifying the presence or lack open/closed is easy, it’s tougher to achieve.

I also use OCP from the micro to macro scale. It can be applied to classes or it can be applied at a module/library level. Most material on the web covers the easier class level OCP. I’d like to cover the latter using some changes made recently to the Moe state machine library.

The Problem

On my current project, I encountered a great place to use a state machine to simplify a bunch of code. The usage of the state machine itself was interesting and I hope to post about it soon. From a Moe standpoint, I found that the way state actions were implemented didn’t suit my needs. First, I didn’t want to centralize enter/exit actions, particularly at the time of construction. Beforehand, you would add entry and exit actions when you built your state machine. This would mean they were all in a single chunk of code, or you would have to pass the builder around. Not ideal. Second, I also wanted to swap out these actions on demand. When the state machine wasn’t in use, I wanted to disconnect state actions so windows didn’t appear based on wayward events (ie, a late arriving error event from a webcam we were using).

The Solution

I revisited Moe to add the functionality I wanted. What I envisioned was a convention for state actions. Any class could have methods following the form “OnEnter” and “OnExit”. These methods would auto-magically be invoked upon entering and exiting states. These classes could also be added or removed as listeners at any time. I decided to call this functionality state delegates.

While working on Moe previously, I had done a lot of work to support the OCP and this can be seen in the Moe.StateMachine.Extensions library. In that library you can find several helpful additions for Moe, such as logging, state watchers, timers, and asynchronous state machine execution. I specifically wanted that functionality to exist outside of the core state machine. Would the hard work of that refactoring pay off and allow me to add state delegates?

The Changes

You can see the changes that were made in this commit. The solution was to add a traffic cop that would wire up to every state and intercept state enter/exits. When one of those happened, the StateDelegatePlugIn would run through the current listeners and delegate to any methods matching the state name.

This huge addition to functionality (in value, that is) was achieved without touching the state machine at all. This is the OCP on a larger scale. We’ve added valuable functionality to a library without modifying the library itself.

How to move towards OCP

It’s tough, if not impossible, to produce code supporting the OCP from the beginning. Before we can abstract, we need to SEE at least a few examples of usage first. If you were to go back and look at past commits, you’d find several that are focused on refactoring to the OCP after several functional additions were already in place. To begin with, the functional additions were intertwined with the state machine itself. By unwinding those dependencies, I was achieving OCP through actual usage. It would have been too much for my brain to try and see the resulting patterns and needs without already having multiple examples.

When I do something like this, I’m looking to make core classes as simple as possible, keeping as close to the Single Responsibility Principle as I can. Something that I should have done earlier was introduce the Extensions library. By forcing myself to move functional additions to a separate assembly, I would have no choice but to support OCP. When thinking of simplifying or SRP, think of the grand Unix commands. Grep, sed, sort, and so on. Have your components do one thing and do it well.