views:

167

answers:

4

For example, say we have a ticketing system that can be configured to offer tickets at normal price, but once you're within X hours of the event, you offer them at a different price (it may be discounted or increased). We'll call this the 'rush price'. Moreover, once you're within Y hours of the event, you offer them at yet another price. We'll call this the 'emergency price'.

The class that represents this configuration information might look like this:

public class RushTicketPolicy {

    private int rushHours;
    private int emergencyHours;

    public RushTicketPolicy(int rushHours, int emergencyHours) {
        this.rushHours      = rushHours;
        this.emergencyHours = emergencyHours;
    }

    public int RushHours      { get { return this.rushHours; } }
    public int EmergencyHours { get { return this.emergencyHours; } }
}

I'm finding it extremely difficult to come up with names for these variables (and properties) that are sufficiently expressive and complete, without reference to the code that uses them and without additional inference.

That is, someone that hasn't seen the rest of the code or know anything about its business requirements should be able to look at the variable names and understand that:

  • Rush sales start X hours before the event, inclusive.
  • Emergency sales start Y hours before the event, inclusive.

What are some names that would accomplish that?

A: 

Name it what it represents ... :D

RushTicketPolicyValidityIntervalLength

Okay, the class has already part of the information. So what about this?

ValidityIntervalLength

Or something similar.

Daniel Brückner
The word *interval* might well be part of the solution, but this doesn't express to what period the interval applies.
Jeff Sternal
+1  A: 

I'm a fan of verbosity here:

DiscountThresholdInSeconds

Based on your edit #1:

If you have a class "Ticket," I would simply give it a collection of discounts:


    public class Ticket
    {
        private List <Discount> m_availableDiscounts = new List<Discount>();
        private decimal m_basePrice = 0m;
        private DateTime m_showTime;

        public Ticket(DateTime showTime)
        {
            m_showTime = showTime;
        }

        public List<Discount> Discounts
        {
            get
            {
                return m_availableDiscounts;
            }
        }

        public decimal BasePrice
        {
            get
            {
                return m_basePrice;
            }
            set
            {
                m_basePrice = value;
            }
        }

        public DateTime ShowTime
        {
            get
            {
                return m_showTime;
            }
        }

        public decimal CalculatePrice(int quantity)
        {
            //Apply discounts here...
        }
    }

    public class Discount
    {
        private int m_thresholdInSeconds = 0;
        private decimal m_percentOff = 0m;
        private decimal m_flatAmountOff = 0m;

        public Discount(int thresholdInSeconds, decimal percentOff, decimal flatAmountOff)
        {
            m_thresholdInSeconds = thresholdInSeconds;
            m_percentOff = percentOff;
            m_flatAmountOff = flatAmountOff;
        }

        public int ThresholdInSeconds
        {
            get
            {
                return m_thresholdInSeconds;
            }
        }

        public decimal PercentOff
        {
            get
            {
                return m_percentOff;
            }
        }

        public decimal FlatAmountOff
        {
            get
            {
                return m_flatAmountOff;
            }
        }
    }


Edit #2 based on question Edit #2

The difference between what you have listed and the code I provided is that yours only allows for two distinct discount periods while mine will support the tiered model. If we really are talking about tickets here, think about it like a timeline:

Now-------------------------------------------------------------------------ShowTime

At any time in that period, you may have surpassed a threshold (checkpoint, boundary, whatever) that qualifies you for a discount.

------------|------Now------------|------------------|---------------|---|---ShowTime

Since ShowTime is the stable piece of information in this time line, you need to capture "distance" from showtime and the applicable discount. The "distance" from ShowTime is the threshold that gets crossed.

Jacob G
I love verbosity too - but given that variable name, does the discount apply before or after the threshold is met?
Jeff Sternal
My reading would be after it is met. If it were to be before, I would call it DiscountExpirationThresholdInSeconds.
Jacob G
Hmm, I am interested in variable names that can express this directly, such that it is unambiguous.
Jeff Sternal
I definitely appreciate the discussion here, and I don't mean to bait and switch with the edits! Indeed, your proposed class design might be superior in cases where it's possible (which it wouldn't be if the threshold information was coming from a different source than the discount information), but the variable name still suffers from the problem I'm trying to solve: *thresholdInSeconds* doesn't express what the threshold stands in relation to (the event), nor does it describe whether the discount should be applied before or after the interval.
Jeff Sternal
This seems like premature generality to me. His method supports 0,1 or 2 discount periods (you can set the discount to 0.) If it's unlikely that there will ever be more than 2 discount periods, why write longer, less clear code to support a feature that won't be needed?
RossFabricant
I'm happy to help (I fret over these things all of the time.) I was thinking that Discount.ThresholdInSeconds together would express what you're looking for. Something more verbose that popped in my head could be QualifyingThresholdInSeconds... I think the "before or after" component of your question is unnecessary, though. As ShowTime is the only possible stable reference point, it should be implicit.
Jacob G
@rossfabricant - Unlikely does not mean impossible. The client/management could end up asking "We want to add a third discount period, that's not too hard is it?" ... and of course they're more likely to ask when you haven't planned for it. If it can be coded to support 2 of something, it can be coded to support indefinite numbers and it's an easy way to cover your ass just in case.
Sean
+1  A: 
public class SalesPeriodStartRule {

    private int mHoursBeforeEvent = 0;

    public SalesPeriodStartRule(int hoursBeforeEvent) {
        mHours = hoursBeforeEvent;
    }
    public DateTime GetEffectiveDate(DateTime showDate) {
        return showDate.AddHours(-mHoursBeforeEvent);
    }
}

public class PricingPolicy {
    private SalesPeriodStartRule mRushRule;
    private SalesPeriodStartRule mEmergencyRule;

    public PricingPolicy(SalesPeriodStartRule rushRule, SalesPeriodStartRule emergencyRule) {
        mRushRule      = rushRule;
        mEmergencyRule = emergencyRule;
    }
    public string GetPriceCategory(DateTime purchaseDate, DateTime showDate) {
        if (purchaseDate > mEmergencyRule.GetEffectiveDate(showDate)) {
            return "Emergency";
        }
        else if (purchaseDate > mRushRule.GetEffectiveDate(showDate)) {
            return "Rush";
        }
        else {
            return "Standard";
        }
    }
}
Brandon
This is from the colleague I mentioned above - I just edited his code to fit the original example.
Jeff Sternal
Though part of me is still holding out for a variable name that can express the entire concept as originally stated, refactoring into two classes and encapsulating the effective date calculation does clarify this, so I'm accepting until someone comes up with a variable name that's just right
Jeff Sternal