Reducing Technical Debt

Code Duplication

Duplicating code can not only be inefficient but can also be dangerous to developers not familiar with the codebase. By centralising shared logic, we make future changes easier with less risk.

Abstraction

Consider the following array sort example that shares the same sort algorithm

const orderedUsers = this.users.sort((a, b) => {
    return a.name > b.name
})

const orderedTeams = this.teams.sort((a, b) => {
    return a.name > b.name
})

We can abstract this algorithm into a reusable and testable sort function. Note that we are passing through sortByName and not sortByName()

const sortByName = (a, b) => a.name > b.name

const orderedUsers = this.users.sort(sortByName)
const orderedTeams = this.teams.sort(sortByName)

Factory Methods

Sometimes when we are abstracting code, we may start to notice patterns. For example, sorting objects by a certain key is a fairly common use case. We can abstract your original Abstraction into a Factory Method that will build a sort algorithm for us based on the arguments that we pass in.

const sortByKey = (key) => {
    return (a, b) => a[key] > b[key]
}

this.users.sort(sortByKey('name')) // effectively (a, b) => a.name > b.name
this.users.sort(sortByKey('id'))   // effectively (a, b) => a.id > b.id

Mixins

Code duplication can also be addressed across multiple files, we can abstract logic into common libraries, such as Mixins, that can be shared between files

Consider these similar methods in two seperate Vue components

// Foo.vue
adminUserIds() {
    const adminUsers = this.users.filter(user => user.admin)
    return adminUsers.map(user => user.id)
}

// Bar.vue
adminUserNames() {
    const adminUsers = this.users.filter(user => user.admin)
    return adminUsers.map(user => user.name)
}

The duplicated logic to return a list of admin users can be abstracted to a Computed Property in a Mixin which can be included in both Vue components.

// userMixin.js
export default {
    computed: {
        adminUsers() {
            return this.users.filter(user => user.admin)
        }
    }
}

We can then import this Mixin into both components and remove the duplicated code in the method

// Foo.vue
import userMixin from './userMixin'

export default {
    mixins: [ userMixin ],

    methods: { 
        adminUserIds() {
            return this.adminUsers.map(user => user.id)
        },
    },
}

Utility Libraries

As Mixins only really apply to similar Vue components, we can also abstract our reusable variables and methods into utility libraries.

Consider the following code that filters a list of users based on an array of ID's

this.users.filter(user => [1,2,4,9].indexOf(user.id) !== -1)

First of all, without the domain knowledge of what these ID's are for, it is hard to understand the intent of this code. We can help by moving the array to a sensibly named variable.

const adminUserIds = [1,2,4,9]
this.users.filter(user => adminUserIds.indexOf(user.id) !== -1)

As it is likely that we will reuse this variable and filter method again, we should move it to a utility library and expose them using the export keyword

// userUtils.js
export const adminUserIds = [1,2,4,9]
export const adminUsersFilter = (user) => adminUserIds.indexOf(user.id) !== -1

We can then selectively import these into our project by utilising Webpack's Tree Shaking

import { adminUsersFilter } from './userUtils.js'

this.users.filter(adminUsersFilter)