Darren Hickling

Stop, Look, Reuse

Published onReading time4 minutesImage sourceNickyPe on Pixabay
Authors

There are many posts on reinventing the wheel in software engineering — there's even a dedicated section on the Wikipedia article — yet I'm chiming in with my own. Why? Because I've seen so much of it!

Examples

Rather than rant on about the problem, I think it's more useful to illustrate some of the examples I have encountered. Let's start with:

CSV Parsing

Comma-separated values are easy, right? Just split and you're onto the next problem! Except when a comma is part of a value, or the file extension is actually used for tab-separated values, or you want to serialise the file with its weird heading names into your clean class definition.

It's surprising how often I've seen this situation. Even more surprising when there are brilliant open-source libraries that have solved these problems and others, particularly streaming large files, such as Papa Parse:

const Papa = require("papaparse")

const csv = `ID,Name
#Oh look, a helpful comment!
1,"Grisham, John"
2,JK Rowling`

const { data, errors } = Papa.parse(csv, {
    comments: "#",
    dynamicTyping: true,
    header: true
})

Templating

Another typical problem: inserting dynamic data into a template. Again, what starts off as a simple solution:

Let's use a placeholder, like {ID}, then find and replace it!

... quickly produces unwanted tag matches and weird work-around logic. There are plenty of libraries that do this very well, like Mustache:

const { render } = require("mustache")

const view = {
    name: "Dave",
    calc: () => 2 + 4
}

render("{{name}} spent £{{calc}}", view) //"Dave spent £6"

This scenario is probably the weirdest for me, as languages such as C# and JavaScript have built-in templating methods, so surely you would think to reuse something similar?!

Dependency Injection

I have seen custom IoC containers. They were not pleasant. That is all.

Data Serialisation

Most modern software communication methods provide plenty of ways to serialise data in a well-defined manner. Circumventing this, like converting an array to a string, JSON-serialising an object, or even creating your own method of serialisation and communication, is almost always foolhardy. There are so many potential issues that are solved in more battle-hardened ways, so take the time to research and use them! If it's boring writing another contract for your business domain object, there is likely something wrong with its definition or implementation, rather than the technologies you are using to send and receive it.

The most common misuse I have seen here is for dictionaries and dynamic objects:

JSON.stringify({
    my: 1,
    complex: false,
    object: true,
    with: null,
    many: "yay",
    keys: undefined
})

Trust me: take the time to understand and define this properly:

interface Better {
    my: number;
    complex: boolean;
    object: boolean;
    "with": number | null;
    many: string;
    keys!: string;
}

Note the definitions of with and keys now; keys is actually omitted using JSON.stringify: did you want that?

If possible, share the contract with consuming technologies, such as hosting a private package on Gemfury. There are even libraries that can generate API contracts for your consumers in the languages of your choice, like GraphQL code generator.

Make Reuse a Habit

What can be done to encourage reuse of libraries and patterns? Try this method:

🛑 Stop

The next time you hit a problem, design a solution and are about to implement it: please stop for a minute. Try and summarise the issue again to yourself — or better, a colleague or team — and see what they say. Even if your proposal still seems valid...

👀 Look

It's amazing how often a quick web search brings up unexpected answers. Wording is important, so try varying the description of your predicament several times before proceeding if nothing arises. Often, you discover new terms for a pattern you previously had no idea existed! Finally:

♻ Reuse

Hopefully by now, you've found the answer to your problem! As ever, try and assemble a working prototype as quickly as possible, testing your weird edge-cases where they are known. With any luck, you will have saved yourself plenty of development and fixing time!

Still No Answer?

Why not publicise the problem and contribute your solution? You may consider the eventual fix trivial, or the edge-case you solved quite unique, but I guarantee your contributions will save at least one person a lot of time, effort and frustration in the future. Think back to how you felt, and I'm sure you will agree that even a one-line comment on Stack Overflow is worth your time.

Thanks for your help in advance!