2/25/14

programming strategy note

I wrote some code to merge todo items in pima. It is about 44 lines — no need to read it, I just put it here so I can copy from it if I need — but the story continues after the code:

function mergeCards(c1, c2, parentC) {
    if (!parentC) {
        if (c1 && c2) throw 'how could two cards get generated with the same id?'
        return c1 || c2
    }

    function cardDiff(c, parent) {
        if (!x) return { deleted : true }
        var d = {}
        if (x.text != parent.text) d.text = true
        if (x.createTime != parent.createTime) d.createTime = true
        if (x.showTime != parent.showTime) d.showTime = true
        if (x.touchTime != parent.touchTime) d.touchTime = true
        return _.keys(d).length > 0 ? d : null
    }
    var d1 = cardDiff(c1, parentC)
    var d2 = cardDiff(c2, parentC)

    function merge(d1, d2, c1, c2, func) {
        if (!d1 && !d2) return c1
        if (d1 && !d2) return c1
        if (!d1 && d2) return c2
        return func(c1, c2)
    }
    return merge(d1, d2, c1, c2, function (c1, c2) {
        if (d1.deleted || d2.deleted) {
            if (d1.deleted && d2.deleted) return null
            var c = _.deepClone(d1.deleted ? c2 : c1)
            c.text = 'CONFLICT----DELETED\n' + c.text
            return c
        }
        return {
            id : c1.id,
            text : merge(d1.text, d2.text, c1.text, c2.text, function (c1, c2) {
                return 'CONFLICT----\n' + c1 + '\nCONFLICT----\n' + c2
            },
            createTime : merge(d1.createTime, d2.createTime, c1.createTime, c2.createTime, Math.min),
            showTime : merge(d1.showTime, d2.showTime, c1.showTime, c2.showTime, function (_, __) {
                return c1.text == c2.text ? Math.min(c1.showTime, c2.showTime) : 0
            },
            touchTime : merge(d1.touchTime, d2.touchTime, c1.touchTime, c2.touchTime, Math.max)
        }
    })
}

Now I was proud that this code seemed like it would handle lots of merging cases in elegant ways, but I was concerned that it would be hard to test, especially since the most smarts were in the least likely things to happen..

..so I decided to make it less smart, but easier to test — no need to read this either, it's about 33 lines — story concludes after the code:

function mergeCards(c1, c2, parentC) {
    if (!parentC) {
        if (c1 && c2) throw 'how could two cards get generated with the same id?'
        return c1 || c2
    }

    function dirty(c, parent) {
        return !c ||
            c.text != parent.text ||
            c.createTime != parent.createTime ||
            c.showTime != parent.showTime ||
            c.touchTime != parent.touchTime
    }
    var d1 = dirty(c1, parentC)
    var d2 = dirty(c2, parentC)

    if (!d2) return c1
    if (!d1) return c2

    if (!c1 || !c2) {
        if (!c1 && !c2) return null
        var c = _.deepClone(!c1 ? c2 : c1)
        c.text = 'CONFLICT----DELETED\n' + c.text
        return c
    }
    return {
        id : c1.id,
        text : 'CONFLICT----\n' + c1.text + '\nCONFLICT----\n' + c2.text,
        createTime : Math.min(c1.createTime, c2.createTime),
        showTime : 0,
        touchTime : Math.max(c1.touchTime, c2.touchTime)
    }
}

Anyway, I find that I do this a lot. I write a bunch of complicated code, and then decide that it would be easier to rewrite the code to do less stuff than to test the code ;)

No comments:

Post a Comment