2
\$\begingroup\$

My intention is to create a nice DRY method (add) which will take care of parsing floats and adding totals internally and will be called by other methods.

I feel like I'm jumping through unnecessary complex hoops here. Can anyone help me out?

PS: the intention is to be able to specify different objects with add, so if I had a label object called 'food' with a credit property I could create a function called addFoodCredit(amount) which would call add( amount, 'credit', 'labels', 'food').

The full code can be seen here.

var dateObject = function() {
    var totals = {
        totalDebit: 0,
        totalCredit: 0,
        labels: {}
   }

    var add = function add( amount ) {
        var args = Array.prototype.slice.call(arguments) 
        var objectReference = totals;
        var floatAmount = parseFloat (args.shift());
        var objectKey = args.shift();
        while(args.length > 0) {
          objectReference = objectReference[args.shift()];
        }
        var currentTotal = parseFloat( objectReference[objectKey] );
        objectReference[objectKey] = currentTotal + floatAmount;
        console.log(objectReference, objectKey);
        console.log(totals.totalDebit)
    };

    this.addCredit = function addCredit( amount ) {
        add( amount, 'totalCredit' );
    };

    this.addDebit = function addDebit ( amount ) {
        add( amount, 'totalDebit');
    };

    this.addLabel = function ( label, amount, type ) {
        var labelName = label + '-' + type;
        if ( ! totals.labels.labelName ) {
            totals.labels[labelName] = 0;
        }

        add(amount, labelName, 'labels')
    }

  this.print = function() {console.log(totals)};

};

var x = new dateObject();
x.addCredit(15);
x.addCredit(21);
x.addDebit(12.42);
x.addDebit(122);
x.addLabel('food', 20, 'dr')
x.print();
\$\endgroup\$
3
  • \$\begingroup\$ Welcome to Code Review. By reading your question I'm not sure if your code works. Do know that your code need to work for your question to be on-topic on Code Review. See help center for more information. \$\endgroup\$
    – Marc-Andre
    Commented Feb 5, 2015 at 17:52
  • \$\begingroup\$ Thanks Marc-Andre, it is working in the pen I have edited to copy the code over in its entirety, I wanted to focus on the add method in the question \$\endgroup\$
    – LiamRyan
    Commented Feb 5, 2015 at 18:05
  • \$\begingroup\$ Thanks for clarifying. I hope you get some good reviews! \$\endgroup\$
    – Phrancis
    Commented Feb 5, 2015 at 19:02

1 Answer 1

2
\$\begingroup\$

The add method is overly complex for no real benefit. It is hitting a thumbtack with a sledge hammer. The add method is used for waaaay to much. It's not clear what it does. I had to spend 5 minutes dissecting what it did. For an 11 line method, that's pretty long.

I understand you are trying to DRY up your code, but you have sacrificed clarity for perceived duplication of code. Adding to the credit and debit totals appears to be duplicated code, when actually it is not. You are better off removing the add method and going for something explicit. What you do want to DRY up is the conversions of amount values to numbers, and perhaps some error checking.

Defining this inside your dateObject class makes ensuring arguments are numbers a quick one-liner.

var toNumber = function(x) {
    var n = Number(x);

    if (isNaN(n)) {
        throw new Error("Invalid number: " + amount);
    }

    return n;
};

Now, your addCredit and addDebit methods become explicit and easy to read:

this.addCredit = function(amount) {
    totals.totalCredit += toNumber(amount);
};

this.addDebit = function(amount) {
    totals.totalDebit += toNumber(amount);
};

The addLabel method flat out confused me for a good while because it delegated to the add method. As a general rule, avoid turning methods into a "utility belt" where they perform more than one task. It makes for confusing code that is hard to maintain and debug.

The addLabel method (as far as I can tell) becomes much easier to visualize and debug as well:

this.addLabel = function(label, amount, type) {
    var key = label + "-" + type;
    totals.labels[key] = totals.labels[key] || 0;
    total.labels[key] += toNumber(amount);
};

And now on to every programmers' favorite subject: naming things :)

You have a "class" called dateObject. Naming conventions in JavaScript dictate that "classes", or more accurately constructor functions, should capitalize their first letter. Secondly, your dateObject class does nothing at all with dates, and is confusing because JavaScript has a Date class. Crediting and debiting amounts has nothing to do with dates. I realize you omitted some code but consider renaming this class to something like Account:

function Account() {
    var totals = {
        totalDebit: 0,
        totalCredit: 0,
        labels: {}
    };

    var toNumber = function(x) {
        var n = Number(x);

        if (isNaN(n)) {
            throw new Error("Invalid number: " + amount);
        }

        return n;
    };

    this.addCredit = function(amount) {
        totals.totalCredit += toNumber(amount);
    };

    this.addDebit = function(amount) {
        totals.totalDebit += toNumber(amount);
    };

    this.addLabel = function(label, amount, type) {
        var key = label + "-" + type;
        totals.labels[key] = totals.labels[key] || 0;
        total.labels[key] += toNumber(amount);
    };
}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the clear feedback and effort put into this answer, it's really appreciated! \$\endgroup\$
    – LiamRyan
    Commented Feb 7, 2015 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.