1

I came across this code today and wondering what are some of the ways we can optimize it.

Obviously the model is hard to change as it is legacy, but interested in getting opinions.

Changed some names around and blurred out some core logic to protect.

private static Payment FindPayment(Order order, Customer customer, int paymentId)
    {
        Payment payment = Order.Payments.FindById(paymentId);
        if (payment != null)
        {
            if (payment.RefundPayment == null)
            {
                return payment;
            }

           if (String.Compare(payment.RefundPayment, "refund", true) != 0 )
            {
                return payment;
            }

        }

        Payment finalPayment = null;
        foreach (Payment testpayment in Order.payments)
        {
            if (testPayment.Customer.Name != customer.Name){continue;}

            if (testPayment.Cancelled) 
            {
                continue;
            }

            if (testPayment.RefundPayment != null) 
            {
                if (String.Compare(testPayment.RefundPayment, "refund", true) == 0 )
                {
                    continue;
                }
            }

            if (finalPayment == null)
            {
                finalPayment = testPayment;
            }
            else
            {
                if (testPayment.Value > finalPayment.Value)
                {
                    finalPayment = testPayment;
                }
            }
        }
       if (finalPayment == null) 
       {
           return payment;
       }

       return finalPayment;
    }

Making this a wiki so code enthusiasts can answer without worrying about points.

5
  • Nope, older .net version Commented Mar 26, 2010 at 16:50
  • Are you looking for performance optimizations or readability optimizations? Commented Mar 26, 2010 at 16:52
  • 1
    LinQ might not give you an improvement in terms of performance, but it would almost certainly improve on readability. Shame you can't use it. Commented Mar 26, 2010 at 16:54
  • How many types of Payments do you have? Is it just Refund and "Normal"? Commented Mar 26, 2010 at 16:58
  • What version of VS are you using? Even if you are using .Net 2.0 from VS2008, you can easily fake LINQ. Commented Mar 26, 2010 at 19:14

5 Answers 5

2
 if (testPayment.Customer.Name != customer.Name){continue;}

That shouldn't be necessary for a start - surely all the payments against any given order relate to the same customer?

I don't like this function at all, if I'm passing a passing a payment_id, then I would only expect to get either that specific payment, or null... None of this searching around stuff...

Sounds to me like you need to think about redesigning a lot of code, and I think it goes well beyond this specific function...

Sign up to request clarification or add additional context in comments.

3 Comments

Depends on the nature of the app. I've seen business apps where an order can have multiple paying customers with varying percentages each one owes. Though comparing by name could cause issues if name isn't a PK.
+1 for that, but given the code we have already seen I think it's unlikely. You're right to point it out though...
I am just getting around the app..there is lot that needs to be done..I think I will get several opportunities to post trivia.
1

It's going to be highly data-dependent. You need to profile this with a "typical" data set, identify the bottlenecks, then consider appropriate optimisations based on your profile data.

4 Comments

I only see one loop (foreach) - perhaps you mean something other than nesting ?
There's a lot of nested conditions in there, which could be removed by taking advantage of the fact that C#'s && and || operators are actually shortcut logical operators, similar to AndAlso and OrElse in VB. It wouldn't improve performance, but would make the code easier to follow. The importance of code readability is often underestimated...
@Martin: sure - I was just questioning the OP's reference to "multiple nested loops", since there is only a single loop. I still think he should profile this first and then decide what to optimise, if anything.
Agreed - though he should really look at a re-write... The idea of having the refund string for example - this would be a lot quicker with an enumeration...
1

If you can add members to the Payment class, add a didRefund boolean which is set to true whenever the RefundPayment string is set to "refund". This allows you to avoid the string compares.

Before the loop if you do initialize finalPayment like this:

finalPayment = new Payment;
finalPayment.Value = -1.0e12

then you can avoid the null test in the loop. (Assumes none of the customers are making negative billion dollar payments)

Comments

1

The first test (if (payment.RefundPayment == null)) is redundant. The second test using String.Compare works with null strings. You can use this "optimization" in the second place you use this comparison in the foreach loop.

Comments

1

You can move one of the conditions into a function of it's own since it's repeated twice (testing for it and its opposite). You can also shove the conditions together and wrap the whole loop in the first conditional. That way you only have one exit point for the function. If that doesn't seem manageable, you can wrap the foreach-loop into a function and just call it that way.

private static boolean IsRefundPayment(Payment payment) {
    return payment.RefundPayment != null && String.Compare(payment.RefundPayment, "refund", true) == 0;
}

private static Payment FindPayment(Order order, Customer customer, int paymentId) {
    Payment payment = Order.Payments.FindById(paymentId);
    if (payment == null || IsRefundPayment(payment)) {
        foreach (Payment testpayment in Order.payments) {
            if (testPayment.Customer.Name == customer.Name && !testPayment.Cancelled && !IsRefundPayment(payment)
                && (testPayment.Value > payment.Value)) {
                payment = testPayment;
            }
        }
    }
    return payment;
}

1 Comment

Omit finalPayment, just write directly to payment. Then you'll lose a declaration, as well as the final if.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.