Images

After reading one of Mark Turansky’s latest posts I remembered an application I wrote a while back that fit into the same image category. His post describes a script he wrote that will download pictures from a camera and sort them. Unfortunately I didn’t have this script (until now) and through multiple transfers of the image library from one computer to another I found myself with many duplicate images.

So some time last year I threw together a simple C# application (sorry non-MS users) that will give you a list of all the duplicate images on your system as well as a quick way to view them to verify they are the same and a way to delete them. The application uses the time stamp that the image was taken to determine likeness. If you have your camera take burst pictures then you will likely see a lot and this is probably not the application for you. However, if you take normal pictures then this can help ensure that you don’t have a bunch of duplicates floating around.

Image Organizer

This code/application is free to use and distribute with two conditions:

1. If it is going to be used in any way to make money you must get my prior written consent

2. Leave the copyright and distribution rule info in place in all places it is found.


Download source: Image Organizer – C# Source

Download Windows installation files: Image Organizer – Windows installation files

Enjoy!


Performance v. Effort Revisited, ceteris paribus

After speaking with Mark Turansky about the original Performance v. Effort post and he gave his impression that my post is confusing because it delivers arbitrary numbers with no explanation of how I arrive at those numbers or what they mean.

Ultimately the post is saying this:
You can’t expect to hire based upon an industry or market standard and end up with a solid company. You must understand your needs (weights) and the abilities (ranks) of candidates in order to find individuals who are a proper fit for your company at any given time.

The numbers are arbitrary because they are used to illustrate a theoretical situation. The rankings and weights assigned to each individual are fictional numbers that are at the discretion of each theoretical company to arrive at. In this case I have illustrated a scenario where Company A places the most value on productivity, sociability, then effort while Company B values fall in the order of sociability, effort, then productivity. These numbers could just as easily fall in any other number of combinations and, in a real world situation, would involve far more parameters than the three listed here. Likewise, the weights are indicative of a simplistic scenario where everyone in the company who’s opinion counts feels the same way. In a situation where there are conflicting views on weights the scenario would be far too complex to model easily. Once again, the weights used were arbitrary and illustrative in nature.

This confusion, I think, arises from my neglect to include an obligatory reference to ceteris paribus. The concept that this is a limited scenario with a very focused view should be qualified and my original post was truly intended to work on a finite and unchanging model. Without focusing on a situation qualified by ceteris paribus you would find yourself in a situation much too complex to illustrate easily.


When the rabbit hole is a dead end

I have had many friends that were musicians, some of which are good enough to make a living doing nothing else. Despite the style, personality, and trend differences of each they all share the same message with regards to song writing: sometimes you write ten songs just to find one that is a keeper. The song writer can perform the ten songs leading up to the one keeper all they want however diluting their musical offering with sub-par works is likely to reduce the overall attraction of the artist. Only by playing the best of their offerings can they hope to attract the largest audience and following.

Software is no different.

Software, like music, is a creative process. Any creative process will produce failures at one point or another but will hopefully also produce successes. It is the ability, as an artist, to let go of sub par work in order to continue on to the prize winner that sets the great software designers from the mediocre. Note however that moving on does not mean forgetting. The lessons learned on the “failure” are often going to be invaluable in designing successes in the future and sometimes the failure may even re-manifest itself as a success in a future endeavor.

A great example of this comes from my personal experience. I recently worked on a project that was attempting to greatly simplify a very complex problem. I spent a good deal of time (mainly thinking while in the car, falling asleep, eating, and other quiet times) designing the application, its structure, and its interactions in my head before I started writing a lick of code. From the beginning I had two paths to choose from. One path was very well traveled and it was quite easy to find applications down this path on the internet (however none of them quite met our needs). The other path was not traveled at all, at least not noticeably. After thinking through the two paths I decided that the less traveled one would be able to give us a better advantage in the context of our goal. Off I went.

It was a dead end. It wasn’t until I was 75% down the less traveled path that I realized that it was definitely the wrong solution for our needs. After going back through the design, shifting things around, and playing with different variations I came to the conclusion that the only way to get the idea working would be to go all the way back to the initial fork in the road and choose the other path. Damn. Discouraged, I pushed the application aside.

After giving the problem a weekend to settle in my brain I returned to it with a couple ideas of how to make it work and, more importantly, other possible uses for the code that would turn it into a success. The ideas to rectify the code didn’t pan out so I turned to a reuse scenario and found that my design was a perfect fit for another function. The irony of the situation is that the ability to recognize the failed code as being useful elsewhere stemmed from an earlier failure. Years ago I had designed a solution that worked well but soon failed to be able to keep up with business demands. It was the experience that I gained through this early failure that opened my eyes to a potential reuse for my most recent failure. So even though my original intent for the application failed, the solid underlying design created an opportunity to plug it into another function with virtually no design changes.

Failures happen, especially in the complex world of software design. Just as the musician is able to reuse certain chord progressions, vocal mixtures, or harmonies from a failed song to create a masterpiece, software designers are able to glean useful portions of code or design concepts from a failed design. When it comes to failures, push them aside or reuse them, but always learn from them. Put simply, as Mark Turansky is fond of saying, good simple code is hard to write.