DEV Community

Ayron Wohletz
Ayron Wohletz

Posted on • Originally published at funtoimagine.com

Wait until you repeat yourself

You've probably heard of "Don't repeat yourself" (DRY.) It's a best practice to avoid duplicate code. That's good. However, applying DRY too early leads to code that is too "tight" (i.e. premature generalization) – it doesn't leave room for future changes. So I propose a complementary rule of thumb, "Wait until you repeat yourself."

The more data points we have, the more realistic abstraction we can make. In my experience, one instance is usually not enough to extract a robust pattern. It's better to wait for at least two repetitions.

For example, here's a React hook in one of my projects.

export function useScrollToBox({onRest, workspaceId}: { onRest?: () => void; workspaceId?: string }) {
    const client = useQueryClient();
    const saveExpansion = trpc.useMutation("workspace.updateBoxes")
    const scrollToElem = useScrollToElement(onRest);

    return ({boxId, focusSelector, expandBox = true}: { boxId: string, focusSelector: string | null, expandBox?: boolean }) => {
        if (expandBox && workspaceId) {
            expandBoxesInWorkspaceCache({
                client,
                workspaceId,
                boxIds: [boxId],
                setExpanded: true
            });
            saveExpansion.mutateAsync({
                workspaceId,
                isExpanded: true,
                boxIds: [boxId]
            })
        }

        const targetElem = document.querySelector(`[data-boxid="${boxId}"]`) as HTMLElement;
        if (focusSelector && targetElem) {
            const focusElem = targetElem.querySelector(focusSelector) as HTMLElement;
            if (focusElem) {
                focusElem.focus({preventScroll: true});
            }
        }
        scrollToElem(targetElem);
        return targetElem;
    }
}
Enter fullscreen mode Exit fullscreen mode

I didn't strain my brain to figure out all the scrolling behavior the UI would need up front. That would have taken days of analysis. And it probably wouldn't account for oddities that popped up during actual usage.

Instead, I duplicated code in all the places that needed to scroll to a box. After iterating on the UI design for a while, the dust settled, and I could see how to factor out this hook.

Programming is an iterative process. I make a mess while figuring out how to do something. Then I'll go back and clean it up for commit. I don't know any developer who has perfect code flow from their fingertips on the first pass. But it may look that way if you only see the final result.

Of course, I’m talking about everyday programming here. Larger-scale system design needs more upfront effort.

Do you program this way too?

Discussion (0)