Suppose you asked someone what they did for a living and they said, “I am a hammer”. You might find this strange. You might also find it strange for them to say, “I am a table saw”. However it would be quite normal for them to answer saying, “I am a carpenter”. 
Far to often we confuse our proficiencies with the tools of our trade with our actual profession. This is not a good outlook. I use the tool not the other way around. I am not the programming language I am the software engineer. 
So why bring this topic up? Because anyone who believes they are defined by the skills they have in their tools will be limited by those tools. Remember this when you get the chance to learn something new.
We do not always get to pick the project we work on

Sometimes a company will halt all development on a project only to restart it at a later (sometimes much later) date. The reasons for this are many and varied but there are a few things to keep in mind which might help you if you ever have to restart an old project.

Find all of the resources involved with the old project. 

This would obviously include the source for the project. It also includes build scripts, tests, requirements docs, and any other support files.
In addition to the files which make up the project it is useful if you can find the systems which were involved in previous development such as build servers and developer workstations. Some parts of the project may not have made it into source control or it may have an unexpected prerequisite to build or run. These may be identified by examining the old build/dev boxes.
You may also try to track down any email chains involving the project. Even if all of the people involved in the original project are gone the company may have kept an archive of their inboxs in case they needed to be referenced for just this purpose.

Determine the state of the project

Once you have all the bits of the project together it is time to determine where the project was when it stopped. This will accomplish a couple of things. First it will help you and those who want to restart the project determine if the restart is actually worth the time. Second it will keep you from accidentally rewriting functionality which is already present but not immediately obvious. 

Setup or create a build process

If the project has a set of build scripts or some manner of build process it should be reinstated on a nightly or continuous integration build machine. If not then a process should be created.
If this is an internal tool then it should copy its binaries (or other end user useful bits) to a build repository. If this project has installers or some other more involved deployment system then these deliverables should be built as part of the build process and copied out to your build repository.
A build created on a dev workstation should only be used by a dev. Only those builds created by a build server (which should be labeling the builds) should be distributed, handed to QA, or shipped to customers. Adhereing to this rule will prevent one off and otherwise unrepeatable builds from entering the wild. 

Are there unit tests for any part of this project?

If you should be so lucky then these are the next items up to reinstate. Tests will help give you an idea of how the various parts of the project are supposed to work (or expected to break) as intended by those who wrote them. They can also catch fatal flaws you might introduce in the future due to a lack of knowledge of how a particular component is intended to be used.

Deploy a build for QA

Using the output of your now functioning build process deploy an instance of this project and the test it. Validate the current level of functionality of the project. If you have a bug tracking system which has records for this old project then check any obvious issues against any open defects.
The goal of this step is two fold. First is to ensure the project is still in sync with any requirements documents and bug tracking systems you may have. Second is to survey for yourself the true current state of the project with a build and deployment which you can now reproduce.
A quick note about build reproducibility. You should always ensure your build process can exactly recreate any arbitrary build which has come before. There are several insidious things which could prevent this ability with the simplest example being files not under source control (possibly some infrequently modified data files or libraries). Should a defect be introduced into files not under source control this defect will effect all new builds including those of older versions or on branches.

Validate the restart of the project

This point may arise earlier based on what you find along the way, if not then now is the time to consider whether restarting the project is worth it. 
It may turn out the project doesn’t actually do what project management thought it did. Or perhaps it does do what project management thought but is at a lower level of development than expected. A great number or severity of defects may also make the project a non starter. The project may have some big external dependency which is difficult to support or expensive to license. Even if none of the previous apply it may be difficult to add the new features project management wants to the project given the way it has been designed and built. 

The last and possibly most important point

If the objective of restarting an old project is to add some small feature to an old but operational deployment you may be tempted to just make the change to the source, build on your local system, and manually update the binaries on the production system. This is very bad idea. 
If you successfully pull off the update, then all is well. If, however, there are complications it will be very difficult to determine if the issue is caused directly by your update, indirectly through its interaction with other parts of the system, or if your update had nothing to do with the new issue at all. Additionally if you made a manual update to a system which is normally deployed via an installer you have now created a deployment which you may not be able to reproduce thereby making QA by another group virtually impossible. 

Parts and Operation

Crane Parts

There are not many parts to these cranes and assembly is simple (with the exceptions noted below). These cranes have a simple frame with arms which fold up for storage. A hydraulic ram supplies the mechanical advantage necessary to lift the load. All you need to do to operate it is lower the arms, attache your load, close the hydraulic valve and pump the ram. When you are ready to lower the load just (slowly) open the valve.

Notes on Assembly

The assembly instructions for these types of shop cranes indicate the mast is to be attached before the stanchions. In some cases you may find if you follow these instructions the stanchions’s holes will not line up with the mast and the base. I believe in these cases the stanchions are intended to be preloaded by the mast. Just loosen the bolts holding the mast to the base, attach the stanchions, and then tighten the mast bolts.

Lifting stuff

engine crane lifting a washing machine

Here an engine crane is being used to lift a washing machine. I was not feeling all that well the day I needed to move this. So I opted for a reduced stress method of getting this washing machine into the back of a truck.

Lifting with these cranes it not complex but there are a few things to be aware of.

The crane even without a load is quite hefty weighing in at upwards of 150lbs.

Since normal rope can lift significant loads and is readily available it is a nice solution for lifting things around the house. While convenient rope can stretch quite a bit when loaded. If you lift with rope be certain to take this into account, otherwise you may discover you cannot lift to the height you need because the line has stretched too much.

The load you are lifting must have its center of mass inside of the footprint of the crane. Otherwise the crane will be tip over.

The orientation of the load may change as it is lifted. You may discover as you raise the load your attachment points are not in as ideal a position as you would like. This is why it is important to inspect the load as it is being raised. The sooner the issue is found the shorter the distance you will have to lower it back down.

If you are moving things inside the house be aware of the load at the wheels of your crane. When the arms are down the wheels at the front of the base are not used (they are off the ground).

Top: arms up. Bottom: arms down (not the floating wheels)

This means the weight of the load (and the crane) is distributed on 4 wheels. If the floor is not level you will be on 3 wheels. Some interior floors may not react well to the pressures the wheels of the lift will put on them.

my injured lineman’s tool

So I was working in the garage installing new lights. I had verified the circuit breaker responsible for powering the circuit I would be wiring the new lights into, no problems here. Before I got around to installing the lights I realized I had other work to take care of first. So I turned the breaker back on as it was also powering outlets I needed, no problems here either.

After I was done with the sidetracking work I turned the breaker back off in preparation for wiring the lights up, no problems here either. Using my lineman’s tool I then cut the Romex line I would be reworking to run my new lights… problems.

Immediately I had lights, not of the useful overhead lighting kind, along with the popping and hissing noises which accompany shorting a live wire. I was also working on a ladder, which in this case functioned as an unnecessary excitement multiplier, which I ungracefully abandoned. The wire was roasted and my tool now had a notch of metal blasted out by the short circuit arc.

closeup showing missing metal

But the circuit breaker was off. Why was there still power?

Simple. I had turned off the wrong circuit breaker. The breaker I shut off did not have any visual manifestations which would indicate I had gotten the wrong one. So I proceeded with my work. The error was not verifying the power was off at the place and time of the work. Had I checked the line right before starting work again (I had several tools which would do this for me) I would have caught the problem.

Instead I am down one pair of pliers. A small price considering other possible outcomes.

The Task

This combination headphone/microphone line has a break in its outer casing.

The broken casing

This causes the wire the catch on things. While the electrical connections are still good this condition is an inconvenience and needed to be repaired.

The Solution

Heat shrink tubing is perfect for this issue, expect I did not have a size of tubing on hand which would fit over the end connections of this wire and shrink down to a size necessary to grip the line.
The line could be cut and the tubing slid over it but this would entail reconnecting 4 electric lines and that is just a hassle.
I opted to use a larger diameter tubing and the build up the area to be covered with electrical tape. The tape alone would not be the best solution for this issue as unprotected it is likely to unravel.

Line prior to shrinking

After the line was taped the tubing was placed and heated. Ideally I would have used white tubing to match the line but this was all I could find without the trouble of ordering more.

The finished line

an ultrasonic cleaner

Ultrasonic cleaners function by bombarding items with sound whose frequency is beyond the range of human hearing. A discussion of the specific mechanism of cleaning is complex and beyond the intent of this post. What follows are some pointers when using a simple ultrasonic cleaner.


Ultrasonic cleaners will impart their cleaning action to the objects submerged (normally in water) inside them. As such you will only be able to effectively clean items which will fit inside the cleaner. Items with unusual aspect ratios (such as rifle barrels) will likely require a more specialized unit as their shape will not be as common.

Some units will also have heaters for heating the cleaning solution. This is an excellent feature and greatly accelerates the cleaning process. The unit pictured at the top of this page will heat the cleaning solution to about 176F (80C). For comparison most residential water heaters will heat your hot water supply to 120-140F. If you use the heating function some of the cleaning solution may evaporate from the unit and condense on the inside of the lid. Thus care should be taken when removing the lid especially if the condensate may contain corrosives (more on this later).

Cleaners will generally come with some type of wire basket for adding and removing items without getting your hands in the cleaning solution. In addition larger units will have a drain valve for emptying the cleaning solution when it becomes fouled or unusable.

cleaner interior


Simply place the items inside the cleaner, then turn it on or set the timer. The unit does not need supervision. Certain types of items are more easily cleaned in these cleaners than by other methods. Objects having intricate shape or edges cleaning brushes could get caught on are good candidates for ultrasonic cleaning.

electric razor blade assemblies are easily cleaned in an ultrasonic cleaner

Often cleaning will be more effective if some type of solvent is added to the water to form a more effective cleaning solution. What you can use in your cleaner will depend on what it was designed for. Most cleaners can be used with household detergents.

cleaner drain valve

More corrosive/awesome cleaners like sodium hydroxide should only be used if the unit is intended for use with them. Even if your cleaner is constructed of a metal body resistant to attack by corrosives (like stainless steel) other components, like the drain valve seals, may not be. In addition a single successful use of a cleaner with a powerful solvent does not indicate the unit is not suffering damage. While not immediately destroying the unit some substances may greatly reduce its working lifespan.

Ultrasonic cleaners come in a variety of sizes and prices. The one picture in the article runs about $400. Other smaller units can be less expensive but may not come with a heating function.

NOTE: this will generally pertain to C# but applies to any programming language which uses similar exception handling (for example Java). This article covers a few misconceptions about exceptions and is not intended as a complete reference. In depth study of this important programming aspect is highly recommended. 


The exceptions a method throws are as important as its parameters or return value. They are part of your contract with the user, even if you are not required to declare them as part of your method definitions (as you are in Java). Too often methods are completely written before any thought is given to the exceptions it should throw. This unfortunate behavior leads to a less than ideal interface for the user.
Many developers believe, and in many cases are taught, exceptions exist to handle rare or infrequent conditions encountered during execution. The truth is as developers we have no control over the circumstances our code is used in beyond the compiler enforcing the existence of our parameters. As such we can never say what the frequency of any use case may be. Thus we can never say if any given case is rare or common.


The correct use of exceptions is to convey our inability to keep our contract with the user as defined by our method signature. Let us consider the following method signature from the Int32 type:
public static int Parse(string s)
This method takes a string representation of an integer and returns its integer representation. Viewing the documentation reveals it throws the following exceptions:
ArgumentNullException – thrown when s is null.
FormatException – thrown when s cannot be converted to an int.
OverflowException – thrown when the representation of s is beyond the capacity of an Int32 to represent.
Each of these exceptions represents a condition which prevents the method from honoring its contract, returning an integer representation of the string parameter, to the user. There is a different exception for each semantically meaningful mode of failure. That is to say each exception represents a different reason the conversion failed giving the caller the ability to make a meaningful decision about how to proceed. The OverflowException can represent failure due to either a value above or below what can be represented by an Int32. As the user would not take different actions based on whether the value is too big or too small we have just one exception to represent both instead of an OverflowHighException and an OverflowLowException.


Using these ideas let us design our own method. Let us suppose we have a type which represents a temperature probe. We might start by writing a class method with the signature:
public float GetTemperature()
[Note: normally we would use a property here but for demonstration purposes we will make this a method. Also, interestingly enough, the CLR doesn’t know about properties so C# converts them into methods during compilation]
What exceptions should this method throw? Anything which violates our contract with the user should be represented by an exception. In this case any condition which would prevent us from returning a temperature will need an exception. We could start with the following:
TemperatureProbeNotAvailableException – thrown if our connection to the probe is lost.
TemperatureOffScaleException – thrown if the probe provides a value beyond what its specification states it can accurately measure. 
Previously when considering the Parse method we said there was no need to have multiple exceptions to represent the high and low possibilities for the OverflowException. Here we also have a single exception to represent an out of range condition. Considering further is there any action our users might wish to take based on whether the temperature probe is off scale high vs low? In this case there is.
If the probe were attached to a heating or cooling system knowing which direction the temperature is off scale would be very meaningful information. For a more awesome example let us say this was a very high temperature probe in the exhaust of a gas turbine engine. Many such probes do not operate correctly until they reach a minimum temperature well above normal ambient. An off scale low condition might be normal while the engine was offline or idle but an off scale high might indicate the engine was running beyond specification and should be throttled down.
Since the direction of the off scale condition is potentially meaningful to the user we should provide exceptions for these conditions.
public class TemperatureOffScaleHighException : TemperatureOffScaleException
public class TemperatureOffScaleLowException : TemperatureOffScaleException
Though the off scale direction of the temperature probe could be useful to the user this might not always be the case. By extending the high and low exceptions from the TemperatureOffScaleException we give the user a choice  If they do not care about the direction of the off scale condition they can choose to catch the base TemperatureOffScaleException. Otherwise if they have code to handle the high and low conditions differently they may catch these derived exceptions in separate catch blocks and deal with them as they see fit.

Aren’t Exceptions Time Expensive?

Depending on the environment the throwing of exceptions can be time expensive, especially if they repeatedly do so in tight loops. The previously mentioned Int32 type addresses this with the TryParse method. 

public static bool TryParse(string s, out int result)

This method does not throw a FormatException. Instead if will return a boolean indicating if the conversion was successful and if so it will provide the converted value via the result out parameter. By using a boolean instead of an exception this call avoids the cost associated with handling an exception.

Does this method keep its contract with its user? Yes it does.
Whereas the Parse method implies by its signature it will return a converted value TryParse implies it will attempt a conversion. This distinction in naming is important in creating an API your users will be able to easily understand.
A simple look through the FCL will demonstrate the occurrence of TryX is very limited. While the TryX methods seem to match the X method in capacity and excel it in speed it fails in code simplicity. The code necessary to support the TryX method is more cumbersome than the a simple X method.


There are various opinions about the role of exceptions and how they are used. What I would like to convey here is exceptions are an important yet overlooked aspect of development in environments which support them. A more in depth study than what is presented here is recommended though simply considering them at the outset of development instead of as a postscript will help in API design.