So-Called Advent Calendar Day 2 - Tabs vs. Spaces

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.

Code sample with mixed whitespace
Whitespace matters because readability matters

On every engineering team I have ever been on, eventually the “Tabs vs. Spaces” debate comes up with strong opinions from both sides. For those who are unaware, the basic argument boils down to how should a tab be represented in code? As 4 space characters, or a single tab character? So today we explore….

Tab vs. Spaces: What does your choice say about you? You won’t believe number 4!

Just kidding - to me, it actually doesn’t matter. But what does matter is the underlying issue addressed in the discussion: code readability. Whether you are on team spaces or team tabs (go spaces!), both sides agree that you have to choose a side - mixing the two is not an option. In most text editors, a tab character and 4 space characters take up the same amount of physical space on your screen. However, some tools do not follow that trend - for example GitHub renders a tab using 8 spaces.

If you mix your tabs and spaces, it may look fine on your editor, but when you go to review it on GitHub, your formatting goes out the window. And that’s why the argument matters - code needs to be readable by anyone who works on it, not just those who have the same setup as your IDE.

So what should you do?

  • Make your whitespace visible on your IDE. That way you can quickly identify when you have mixed whitespace
  • Choose a side! It doesn’t matter which, but just choose one that your team agrees upon and then never discuss it again. If you can, make it a part of your commit process to automatically format your code so no one has to think about it.
  • If you can’t choose a project wide rule, then at least be consistent within each file. If a file is using tabs, keep using tabs. If it’s using spaces, keep using spaces.
  • If you want to fix a file, make a commit that is just a whitespace commit before you make your changes. That way, when someone reviews the pull request it’s easier to see what changes you actually made vs. which lines were touched only because of the whitespace changes.

So remember, it doesn’t matter what side you are on as long as you are consistent! And consistent code is readable code and that’s what matters the most!

…is everyone gone?

The correct answer is spaces. A space is a space everywhere and you never have to worry about it formatting differently. Also if you use tabs, you will still need to use spaces and will end up mixing the two anyway. This is especially true for any line of code that you need to break up into multiple lines and with tabs you won’t be able to align things nicely. And if you are worried about the number of characters, then you should be minifying your code and then this won’t matter anyway.

See you tomorrow!

So-Called Advent Calendar Day 1 - Static Interfaces

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.

Picture of Lisa Simpson looking at sign saying: Keep out. Or Enter. I'm a sign, not a cop
Sure you can do it, but is it a good idea?

Some time ago I was working on a fix for a bug and as usual I began with trying to see if I could reproduce the bug in a unit test. I forget the exact nature of the bug, but I remember the method in question called out to a fairly complex service class that performed a lot of unrelated logic. Also, I remember that the service class wasn’t really related to bug, but it would throw an exception if the test didn’t include the appropriate setup.

Naturally, my first thought was to use the StubAPI or an interface to stub out the service class. Unfortunately the method was static, so that was not possible as it was currently written. I started considering creating an interface and wrapping the static methods in instance methods so I could mock the class when I realized that the class was already implementing an interface.

But all the methods in this class were static. And the interface it was implementing wasn’t empty, it had several methods in it. As far as I knew, interface methods needed to be implemented using instance methods - you can’t have a static interface method. Yet this class was compiling and had been for years. What’s going on here? Can static methods satisfy an interface?

To test this, in my scratch org I defined a very simple interface:

public interface MyInterface {
    void doTheThing();

Then I tried implementing that interface using a static method:

public with sharing class StaticImplementation implements MyInterface {
    public static void doTheThing() {
        System.debug('I am static!');

And it worked! The static method fulfilled the interface! It compiled! I thought to myself that this will surely throw some kind of runtime error if I tried to use this interface. But to my surprise it does not; the interface will actually call the static method:

MyInterface staticImp = new StaticImplementation();
staticImp.doTheThing(); //Outputs "I am static!"

And to confirm, this isn’t just some weird Apex quirk that allows you to call static methods from an instance of a class. I tried doing the same without the interface, constructing the implementing class directly:

StaticImplementation staticImp = new StaticImplementation();

//Throws a compilation error: "Static method cannot be referenced from a non static context: void"

I can’t find anything suggesting that this is expected behavior and I couldn’t find anything suggesting this was a bug either. The first thing I thought was “Great! I found a trick that allows me to mock static methods in a test!” I started creating my mock class and my unit tests when I paused to remember a quote from one of the greatest movies of our time:

Yeah, but your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should. - Dr. Ian Malcolm, Jurassic Park

If there is anything I have learned in my career, being “clever” is generally a red flag. It is so much more important for the maintenance of your code that it is intuitive, that it makes sense to other developers (including your future self). How much time have you spent trying to fix “clever” code that made no sense, that left you guessing at the intent of the original author? This was exactly the kind of thing that could confuse someone else later on, or even worse, that could break in a future release since it leverage

To be honest, I don’t actually see Salesforce fixing this issue - just delivering the change could potentially break a bunch of code in the wild that happens to take advantage of this (purposefully or not). But just because you can do something, doesn’t mean you should. Next time you are feeling clever, take a second to consider what that cleverness might cost you later.

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.