Engineers - toolmakers

Mechanical engineers are often referred to as toolmakers. When I trained as a mechanical engineer a large component of the training was making tools. In mechanical engineering a tool is not neccicarily a hammer or a screwdriver - it also includes specalized vices, clamps, collets, templates, packing blocks etc. You often make tools in order to manufacture other things. With a simple lathe and some basic elements you can build up a complex toolkit that lets you build almost anything else. Whan you want to make something you assemble these elements into a "jig" of some kind that helps guide the work to get accuracy in the finished product. In fact the nr. 1 job vocation for mechanical engineers was to design and build factory production lines - themselves a kind of tool for making other things. And factory lines are often built up lego-like fashion from off-the-shelf actuators, motors and sensors.

In software engineering we also build tools. We build tools to help non-programmers achive higher productivity. We also sometimes build tools for other developers to use - frameworks, utility functions etc. In my experience the most successful and productive software has been software designed as a proper tool. But what does proper tool look like?

Building a tool for developers is very difficult. A simple approach to building tools is to take something you know, think of the parts of that thing that you imagine could be different for someone else and make a wrapper (or framework) with spaces for others to put their custom code into. This means a lot of tools are built to "wrap" other code. It seems to be a relationship based around who is the function caller and who is the callee. It is a relatively simple aproach because you usually start with something specific that already works, and you can incrementally make something more generic as you go.

My observation is successful tools often invert this relationship. The caller is often user code, and the callee is the tool. This allows the tool to be used within many different contexts. When the tool is the caller and the user code is the callee, the user code is often written in a way that only makes sense in that context. It's difficult to write user code that runs within a framework without that code being integrated with that framework (and thus reusable outside that context). So you end up with business logic that can not be run outside the context of the tool or framework.

Good tools seem to be a collection of functions (a toolkit) that the user can pick and use where appropriate.

Failures

Think about tools that you have used as a developer that feel awkward, clunky, get in the way or end up missing a feature you specifically require without an easy way to work around that. Are you trying to fit your code inside a framework of control?

Good tools

Here are some indicators that you know you are using a good tool:

  • You can use part of the tool without rewriting your code to work "inside" the tool.
  • You can incrementally introduce the tool without fundamentally refactoring your whole code.
  • You know how the tool works internally (or at least have a good idea) and you could write it yourself, but it's easier to use the tool.
  • Parts of the tool (or toolkit) can be used independently from other parts. As a user you choose how much integration you want.

Users

Now with that in mind, instead of thinking about users being programmers think about users being non-programmers. How can you apply these principles to the code that you write for non-programmer users? Can you give your users a toolkit - a collection of functionality that they can use to assemble their own process? Tools that they can understand exactly what they do, that they can swap in and out of their workflow as needed and that are simply easier than doing it in a spreadsheet. Can you avoid writing a monolithic application that wraps all the functionality the user wants, but constrains them to only perform workflows defined in the application?

General solutions

One thing I hear all the time is that we developers need to make our code more general so it can be used for many different things. However there is little talk about exactly how to make code more general. Typically I see developers making code more general by wrapping that code in a "framework". This can be as innocent as packaging functions inside a base class and making that class available for inheritence, all the way up to building a full-fledged framework. When code is wrapped like this the wrapping code ends up being the locus of control and the user ends up releasing control to the wrapper.