Tilt and Flow

In the book Flow by Mihaly Csikszentmihalyi (pronounced “Me-high Cheek-sent-me-high”), the author dives into the joy we find from achieving “flow” while engaging in an activity. I think this is one of the main reasons why coding is so satisfying: we can dive into creative, puzzle-like tasks that we can solve in small chunks while getting immediate feedback on the results. And as we get better at programming you start to see your own progress.

Picture of person looking at stars
Behold! I am one with the universe! This problem that used to take me 3 hours to figure out now only takes 2.

This feedback loop can be addicting. Have you ever been grinding through work items and suddenly find that the sun has gone down? Ever thought to yourself “Maybe just one more ticket, I’m on a roll here,” even though the office has closed an hour ago? That’s the joy of flow. And largely, it’s a good thing. It is such a gift to be paid to do something that can bring you such satisfaction.

But when you hit a roadblock, your flow state starts to go away. And not unlike a drug addiction, you may find that your mind and body begins to spiral as you try to chase that high.

A few days ago I found this happening to me. I had very few meetings so I could focus on working on numerous work items and soon found myself in that “flow” state. The causes of bugs were becoming obvious, my code was working after only a few tries, and the way everything flowed in the application just seemed to make sense. Another developer reached out to me asking me why something wouldn’t load in a Visualforce page and in the splendor of the flow state I thought “I will solve this in a few minutes, for I am Flow.”

4 hours later I had made no progress out what was wrong. I was enraged and angry thoughts filled me head.

Picture of an angry ferret
This application is dumb. This job is dumb. I hate programming and I hate you.

My wife brought me back to earth, we sat down for dinner, and half an hour later I figured out the problem in 15 minutes.

What happened? My flow state had turned into tilt. Tilt is a termed used to describe the frustration felt from doing an activity over and over again and only getting negative results.

The problem with the flow state is that it doesn’t leave much room for reflection. I found myself reading the same documentation over and over again, even though my answer wasn’t in there the first time. I kept repeating the same steps in the application, even though it wasn’t producing the outcome I needed. I would write the same methods, read the same debug logs. And when you’re working in Salesforce, there’s also all that loading time between compile and execution. Without any progress, all of that adds up and gets infuriating. But I was too stubborn, too arrogant to stop for to reflect.

I kept thinking, “If I just work harder, I will figure this out. I am smarter than this.” I wanted to stay in that flow state, but the truth is that was gone about an hour into it. I was quickly losing perspective, slowly becoming enraged, and no closer to a solution. I was chasing that flow high. I was tilted.

Picture of stress
No no, this isn't how this is supposed to work at all

It was only after I had a chance to reset was I able to figure it out. When I returned, I outlined what I had done already and tried a different approach. I wrote down what went wrong, took notes, and basically took my time. Without resetting, I wouldn’t have been able to reflect on what I was doing and probably would have spent a few more hours before going to sleep frustrated, too angry to even learn from what I already did.

Looking back on this, it seems so obvious and childish. “Calm the hell down, Sean, it’s just code.” But we’ve all been there, we’ve all found ourselves in that headspace of frustration, screaming internally “WHY CAN’T I FIGURE THIS OUT.” And so I wanted to share this story to encourage you, and also to remind myself, to walk away. When you start to get tilted, your brain is basically inhibited and can’t perform at the level you need. Walk away and you’ll probably save yourself many many hours of frustration.

Time(zones), why do you punish me?

When it comes to Date values, we typically think of them as timezone agnostic. However, when comparing a Date value to Today’s date, the timezone does matter. When “Today” ends depends on where you live and if you’re not careful, you could be locking out users from a deadline sooner than you expect.

For example, let’s say you are accepting applications until 7/31/2019 and your Apex controller validates this using System.today:

Boolean deadlineHasPassed(Date deadline) {
    return deadline < System.today();
}

If your applicant’s user is in the GMT timezone, that means they will be locked out if they apply any time after 5pm PST on 7/31. Meanwhile, anyone with the PST timezone will have an extra 7 hours to apply. To give everyone an equal time period, you may want the deadline to actually be until midnight on 7/31 in PST.

You could easily fix this by changing the deadline to a Datetime field type so that you can take timezones into account, but that’s not always an option. Your deadline could be based on an standard field like EndDate on Campaign and you typically don’t want to replace a standard field with a custom one. You run the risk of other integrations relying on the standard field being populated, so you put yourself in a position where you have to constantly keep your custom field in sync with the standard one.

As a proxy, you could use the timezone of the org to figure out when midnight is and compare that to the current time. Sounds easy, right? Well as I quickly found out, there aren’t any standard Apex methods that allow you to get a time based on a specified timezone. So here’s what I needed to do:

  • Figure out the current time using the Datetime.now().getTime() method, which returns you the number of milliseconds January 1, 1970, 00:00:00 GMT. This is an absolute time that is unaffected by timezone.

  • Instantiate a DateTime object using the midnight of the deadline given the org’s timezone, convert that to GMT, and then use getTime() to compare it to the current time.

I had some trouble find the code on how to do this, so here’s mine:

Boolean deadlineHasPassed(Date deadline) {
    Timezone orgTimezone = Timezone.getTimeZone([SELECT TimeZoneSidKey FROM Organization][0].TimeZoneSidKey);
    Time midnight = Time.newInstance(23,59,59,999);

    //Get the number of seconds offset between GMT and the org's timezone
    Integer offsetSeconds = orgTimezone.getOffset(deadline) / 1000;

    Long deadlineTime =
        Datetime.newInstanceGMT(endDate, endTime) //Get midnight in GMT
            .addSeconds(-offsetSeconds) //Add the offset seconds so that you can get midnight of your org's timezone in GMT time
            .getTime();

    Long currentTime = Datetime.now().getTime() // get the current time;

    return deadlineTime < currentTime;
}

Now you can compare the current time with the end of a day without having to worry about timezones! I hope this saves someone some time (pun definitely intended).

Stop Fixing My Features!

When I hear the phrase “That’s not a bug, that’s a feature!” I typically imagine that the speaker is a developer defending their code. But sometimes it’s the end user that’s taking advantage of that bug to get the system to do what they want.

Intention vs. Actual Use

Consider the following pseudocode for validating an amount on a line item:

if (lineItem.value == null || lineIem.value < 0) {
    throw LineItemException('Line item value must be populated and cannot be 0 or less');
}

The if statement only prevents values that are null or less than 0, but it actually allows a value of 0. The exception message, however, indicates that 0 is also invalid. To me, that exception message indicates the true intention of the code, meaning there must be a bug in the if statement. Noticing this, I went ahead and fixed the if statement to include 0:

if (lineItem.value == null || lineIem.value <= 0)

However, when this code was released, a bug was reported from the end user.

Something changed in the last release, I can no longer add line items with a 0 value. We’ve been doing this to adjust Opportunities that went from Closed Won to Closed Lost so that we can capture the fact that the line items were part of a deal that happened, but didn’t actually get sold.

My first instinct was to respond with “No, you can’t use it like that, you need to change your process.” This is also probably why I am not a product manager. But that’s not necessarily the correct response. That customer may have thousands of line items like this and this process may be ingrained in their training. They may have built customization that relies on this “feature”.

Just because a bug exists doesn’t necessarily means you should fix it. Imagine if Salesforce decided to completely disable URL hacking. Sure, they may not be officially supported, but they are used by countless orgs! I’ve seen at least one in every single Salesforce org I have ever worked in. So while it’s not necessarily a “feature”, it has become one that customers rely on. So when you should fix a bug?

To Fix or Not To Fix?

Before fixing a bug, you should do some research as to how pervasive the bug is. Here are some questions I like to ask myself when it comes to fixing bugs:

  • What will break as a result of this bug? i.e. What would break if line items had a value of 0?
  • How pervasive is the bug? i.e. How many line items actually have a value of 0?
  • Is there a work around for this bug or does it create a blocker?
  • How many people does this bug effect?

And now, something I didn’t ask before:

  • What would break if we DO fix this bug?

It’s an uncomfortable question as the answer can go against the vision of what your product should do. Do you fix the bug and risk angering the customer or do you leave the bug and possibly create future constraints on what the product can do in the future? Of course, the answer will vary from case to case as you weigh out each alternative. But next time you find yourself thinking you should quickly fix something that you run across, stop and ask yourself if someone thinks that bug is a feature.