Every new technical product, and every modification to an existing technical product, involves transforming an expected input into a desired output. Defining and implementing these transformations are software development.
When I set out to develop software, before I even consider writing a line of code, I define everything: the problem I’m trying to solve, the ideal solution, and everything in between. I try to spend more time thinking about what I am about to write than I do writing it.
Often, someone else—a diligent project manager, a dissatisfied customer—has already defined the problem and/or the solution, and have usually done so in a user-oriented way. My job is to complement those definitions by defining them in a software-oriented way, framing the entire experience as one or more inputs leading to one or more outputs.
The input may be an HTTP request, or it may be the movement of a cursor; the output may be a new record in a database, or it may be an underline appearing beneath some text. Literally and explicitly, in great technical detail, I identify the inputs and output and map out transformations between them. I do this work in my head, or on paper, or by speaking out loud to a colleague or a rubber duck.
A high-quality transformation is easy to understand, easy to maintain, and easy to modify in the future. A high-quality transformation is concise and direct. It is composed of small, dedicated components, working in isolation and in series. It is easy to analyze. It involves few branching paths. If branches are necessary, they occur as early as possible.
Transformations are fractal. A user’s input may beget more inputs, to frontend frameworks and third-party APIs and backend data stores. Each of these inputs has a corresponding output, one nested with another. They are all transformations, worthy of these same considerations.
You can maintain quality in your transformations by following the Rule of Least Power. If you can solve a problem declaratively, your solution will be easier to understand—for others, for you six months from now, for you six minutes from now—than an imperative solution. This means JSON over
Defining your inputs and outputs before you begin to compose your transformations also sets you up nicely for test-driven development. You can write a test proving that, given Input A, you receive Output B. Then you can write the simplest possible transformation to make that test true. When you’re done, you can prove that you’re done, and you can go do something else.