Tell Don't Ask
Published on

Importance of encapsulation

Authors

Arrange

Imagine you have to build a PIN code verification system for your credit card. Would you go around and let everyone see you PIN code? That is like a guessing game. You don't tell everyone this is my PIN code, now you guess it. No! You hide it and protect it with your life. You bury it so deep that it would take whole Inception (movie) group trillion years to extract it.

Here is how the initial code looked like. Of course some stuff is not shown to make it more readable, but more-less it was like shown.

class PurchaseController extends Controller
{
  public function store(Request $request)
  {
    $purchase = Purchase::createFromRequest($request);

    $purchase->complete();

    return $purchase;
  }
}

Given task was super simple. Someone should just add validation before we create a purchase. Super simple, right? Nope, I was wrong. Most time wasted on two lines of code in history of the universe. Tony Stark could probably write all software for his company faster than how much was spent on those two lines of code.

So this smart colleague of mine, let's call him Achmed the Code Terrorist (reference to Achmed the Dead Terrorist), wrote this piece of crap.

class PurchaseController extends Controller
{
  public function store(Request $request)
  {
    $creditCard = $request->user()->creditCard;

    abort_if($request->pin !== $creditCard->pin, 403);

    $purchase = Purchase::createFromRequest($request);

    $purchase->complete();

    return $purchase;
  }
}

When I saw it, I've marked it as bad, requested changes, explained what is wrong with it, remind him how we talked over and over again about encapsulation. He said "OK, I understand. Let me fix it!". I was so happy and proud that I was floating in the air (impossible because I'm super fat, seriously, Cartman fat).

Only a minute later I've received an email notification from GitHub to review the code for the same feature. I knew it was too fast to be fixed, but Achmed the Code Terrorist even sent me a message over Slack saying it was fixed. I've opened the pull request and only change was this.

class PurchaseController extends Controller
{
  public function store(Request $request)
  {
    // same

    abort_if($request->pin !== $creditCard->pin(), 403);

    // same
  }
}

Were you able to spot it? Thank science and logic that we have GitHub and diff, so I can see it because it was marked with different color. Otherwise, I'm not sure I would've been able to find it. Steam started coming out of my ears. I've started pulling my hear. I think that company should pay me one hair transplant because I now look like LeBron James. Jeff Bezos in 2021 looks like he has more hair than LeBron and me combined after looking at that crap code.

After wasting additional 4 hours trying to explain to Achmed the Code Terrorist how he should do it, and him fighting back with various links and references to countless books where he twisted what the author said out of context, I was happy that it was finally over. I've approved the pull request and everything went back to sunshine and rainbows. I was so proud of myself that I finally figured out how to communicate during code reviews and avoid frustration.

So after Achmed the Code Terrorist pull request was merged, I've submitted pull request and asked another colleague to approve it. And here is how the code looks like now.

class PurchaseController extends Controller
{
  public function store(Request $request)
  {
    // same

    abort_if(!$creditCard->pinValid($request->pin), Response::HTTP_FORBIDDEN);

    // same
  }
}

class CreditCard extends PaymentProcessorCreditCard
{
  public function pinValid(string $pin): bool
  {
    return $this->pin === $pin;
  }
}

Super simple, but there is no exposing internals to everyone and letting them decide on what to do. This is called Tell Don't Ask principle. You are not telling everyone your PIN code for your credit card. You are just saying true or false. And if someone is lucky enough to guess it with only 3 attempts, then he deserves to steal from you. But chances for that happening are very slim.

It is like a foreplay with the girl you like. When she asks how tall are you, you never say how tall you really are. You always say something like "What do you think?" and let her guess for a while. And to her guesses you only reply with yes or no.

Hope this makes sense to anyone. If not, then I don't care. I just needed to get it out of my system.

Here is the picture of Achmed the Code Terrorist.

Remember his face. You will probably meet him during your career.