So-Called Advent Calendar Day 14 - A Glaring Plot Hole in Beauty and the Beast

In the spirit of the holiday season, this is a series of short blog posts covering random things I have learned while doing Salesforce development, one for each day of Advent.

Chip from beauty and the beast
The time frames in Beauty and the Beast raise some serious questions

Beauty and the Beast is one of my favorite Disney movies that I will watch every few months or so. Something that always bothered me was the idea that the curse on the castle would be permanent after the prince turned 21:

Which would bloom until his twenty-first year. If he could learn to love another, and earn her love in return by the time the last petal fell, then the spell would be broken. If not, he would be doomed to remain a beast for all time.

But during Be Our Guest Lumiere let’s us know how long they have been cursed:

Ten years we’ve been rusting, needing so much more than dusting, needing so much more than dusting…

So an 11 year old child was transformed into a beast for not letting some random stranger into his house in the middle of the night? If I don’t recognize you or you are not coming out of a delivery truck, I am not answering the door even if it’s the middle of the day! Seems a little unfair.

The live action remake tries to remedy this by making the prince an adult before he is transformed and changing the lyric in Be Our Guest to “Too long we’ve been rusting,” which makes me think that Disney realizes the ridiculousness of this idea.

But recently I saw a clip from Beauty and the Beast: The Enchanted Christmas in which we get to see the scene where Prince Adam transforms (yeah that’s his name! Stop calling him “beast”, Belle. That’s really rude).

Ok, the Prince is a real asshole, maybe he did deserve this curse. But if we consider this canon and Prince Adam was a kid when this all happened, then what about Chip? When the Prince transforms back into a human he is is an adult. But Chip is still a child, and he looks like he is 4 or 5, tops.

Since he was transformed into an inorganic teacup, did he not get to age? Is he now a 14 year old trapped in the body of a 4 year old? He’s may still act like a child, but he also has 10 additional years of experience.

Also why did the witch transform the children and the dog? What the hell did they do wrong? Even the argument that the staff let Prince Adam get spoiled doesn’t hold much weight - he’s their employer and his title implies he is also has power of their lives. Come on now.

Speaking of the children, who are all these children in the cupboard?

teacups sleeping in cupboard

I counted 22 cups in there. Are they running an orphanage in this castle? Were these children working as servants? Or were they born as cups and later transformed into humans? Either way, they spent a majority of their lives as teacups. Do they long for their cup form days?

These are really important questions and unfortunately I don’t think we’ll ever get the truth.

So-Called Advent Calendar Day 13 - White Whale: The Apex Rules Engine Part 1

In the spirit of the holiday season, this is a series of short blog posts covering random things I have learned while doing Salesforce development, one for each day of Advent.

Throughout my career I have built many MVPs that have never gone anywhere. Some of them turned out to not be as useful as we originally anticipated, but there are a select few that I think really had something to them. Either I left the company or shifting priorities prevented us from starting on the next iteration. One such product is The Rules Engine.

One of my favorite declarative features in Salesforce are Workflow Rules. Being able to define actions that run based on criteria without having to write a single line of code can be really useful, especially when that criteria isn’t set in stone. This lets you respond to changes quickly with some level of confidence without having to test the underlying workflow engine every time criteria is a changed. (There is some debate to be had about how much you should test a workflow rule itself, but that’s for another time).

For one job, based on a customer’s contract, certain pricing was created. Not only was this based on the contract with the customer, but also based what the customer’s customer’s profile (e.g. account age, reward points, etc.). At first we just handled this with if statements in the code, but as the customer base grew, so did the complexity of code. Not only were there more permutations because of the increasing number of contracts, but the contracts themselves were getting more complex. Clearly if statements were not enough.

The newest customer had a particularly complex contract where customer pricing was based on the “levels” of their customers (i.e. Bronze, Silver, Gold subscription) and were only eligible for the pricing if they met certain criteria. (I’m making some of this up but it fits the general complexity of the criteria). This seemed like a good opportunity to create some kind rule engine. We first broke down the criteria into “rules”. For example:

  • Bronze Subscription gets 15% off IF:
    • Account is at least 3 year old
    • They have 100 reward points this year
  • Silver Subscription gets 25% off IF:
    • Account is at least 2 years old
    • They have 50 reward points this year
  • Gold Subscription gets 25% off IF:
    • Account is at least 1 year old

To make things more complicated, sales reps wanted to be able to override the criteria and have the discretion to just give someone the discount. So for all these rules there’s an “OR if the rule is overridden for this customer”. To make things even more complicated, these rules weren’t set in stone, so the combination of the rules were subject to change.

The discounts for these customers were calculated in bulk so this information had to be calculated on the fly per customer. A workflow rule wasn’t enough, but the evaluation of criteria in a workflow was just what we needed. I wanted to say if 1 AND 2 AND 3, then this is person is eligible for the discount for their level.

The first thing we did was break down the logical components. Each level was like a Discount Rule and each rule had criteria that had to be met. For example, the “Bronze Subscription” was a type of Discount Rule and it had two criteria:

  • Account has to be 3 years old
  • Reward Points has to be at least 100

By breaking these down into logical components, an sObject model began to emerge:

  • Discount_Rule__c object
    • Name - e.g. “Bronze Subscription”
    • Discount_Amount__c- e.g. 15%
    • Logical_Statement__c - holds the logic statement i.e. 1 AND 2 AND 3
  • Criterion__c object
    • Discount_Rule__c - the parent discount rule this criterion belongs to
    • Rule_Number__c - i.e. the number to represent this criterion in the parent logical statement field
    • Type__c - e.g a picklist with the values “Account Age” and “Reward Points”
    • Condition__c - the value that must be met for this criterion (i.e. 3 for account years, 100 for reward points)

With this structure, we could now represent our discount rules as sObject records. For example

  • Discount_Rule__c object
    • Name = “Bronze Subscription”
    • Discount_Amount__c = 15%
    • Logical_Statement__c = (1 AND 2) OR 3
  • First Criterion__c
    • Discount_Rule__c - “Bronze Subscription”
    • Rule_Number__c - 1
    • Type__c - “Account Age”
    • Condition__c - 3
  • Second Criterion__c
    • Discount_Rule__c - “Bronze Subscription”
    • Rule_Number__c - 2
    • Type__c - “Reward Points”
    • Condition__c - 100
  • Second Criterion__c
    • Discount_Rule__c - “Bronze Subscription”
    • Rule_Number__c - 3
    • Type__c - “Override”
    • Condition__c - true

Now that we have our rules, we now need to create the engine that would take a customer, evaluating them based on this criteria and their subscription level, and then return the appropriate discount.

In the next part, we’ll discuss how I used the Composite Pattern to build the engine with Apex.

So-Called Advent Calendar Day 12 - Planning with Fermi Estimation

In the spirit of the holiday season, this is a series of short blog posts covering random things I have learned while doing Salesforce development, one for each day of Advent.

I remember in science class we would do these things called Fermi Problems. Basically questions with numerical answers that required quick estimation and no time to do any research. For example:

How many people would it take to lift a school bus?

To start, you would start to list out orders of magnitude to get a starting point. Could 1 person lift a bus? Definitely not. 10 people? No way. 100? Hmm, I don’t think so. 1000? Yeah that’s probably more than you need. And so we can probably drill down the answer to somewhere between 100 and 1000.

With research, the answer is way easier. We could look up the weight of an average bus, how much the average person can lift, etc. But the point of the exercise is that you don’t have this information on hand and need to make an educated guess.

Most of the places I have worked go through some sort of long range planning. As a developer I am often asked “how long do you think this will take?” Without the requirements outlined except for high level end goals, it can be overwhelming to give an estimation. Too small and you over commit the team. Too large and it looks like the project isn’t worth the cost at all.

Of course I would love to have more information, but the reality is that I don’t always have that luxury. Maybe Fermi Problems can help us?

Take a look at an ask and start thinking about time frames.

Could I finish this in an hour?
In a day?
In a week?
In a month?
6 months?
A year?
2 years?

Eventualy you’ll hit a point where you’ll think “Okay, I would hope I’d be done at that point!” and you can start to drill down. If that time period is too long, then you can begin to break the task itself down to more digestible chunks and estimate those.

You should of course try to get as much information as you need and push for research when it is possible. But we all know that won’t always be an option. So if you find yourself paralyzed by an estimate, approach it like a Fermi Problem. Sure, saying this will take “6 months to 2 years” is probably way too big of a gap, but at least you have a place to start narrowing things down.