Łukasz Makuch

Łukasz Makuch

When to cut carrots in half?

A long time ago I heard a joke that I recalled recently while thinking about programming.

I don't remember it in details, but the overall meaning is preserved. Here it goes:

Two friends were talking about carrots:

- Jim, why do you always cut carrots in half, when you want to boil them?

- That's simple, Tim. I do it because my mom was always doing that.

Tim got a bit confused, so he decided to ask Jim's mom about that:

- Jim always cuts carrots in half. He told me you always do it. Why is that?

- I don't know why does Jim do it, but I was doing it because the pot I had was too small.

When I was doing my very first steps in software development, I didn't have too much experience with different programming languages. The vast majority of my code was written in PHP. I was lucky enough to read books that improved my skills a lot. That great literature on programming was mostly based on Java or similar languages. Some of those fantastic books were released more than 10 years ago.

I find neat solutions valuable, so when I was facing a problem I read about in a book, I was doing my best to apply that clever solution I found in the book. It all looked right and most of the time it was the best thing I could do. However, sometimes that solution was addressing a problem I didn't have. I didn't know about it, because I didn't know any alternative solution.

If I needed to check whether a person meets some requirement, I'd look at something like the following example.

public interface PersonTester {
    public boolean metBy(Person p);
}
public class ThreeLettersName implements PersonTester
{
    @Override
    public boolean metBy(Person p)
    {
        return p.getName().length() == 3;
    }
}
PersonTester requirement = new ThreeLettersName();

Then I'd write something similar in PHP. I would not consider anything like this.

$meetsRequirement = function ($person) { return mb_strlen($person->name) == 3; };

Why? Because I didn't see it in those books written by people a lot smarter than me. Why wasn't it mentioned? Does it mean it's a bad solution? I don't think so. There's an explanation that makes much more sense. Their pots were too small. When those books were written, Java didn't support code like this:

Predicate<Person> requirement = p -> p.getName().length() == 3;

Something like this wouldn't look serious to me.

$person = (Object)[
  'name' => 'Jim',
  'email' => 'jim@domain_of_jim.com',
]

The correct way I knew was something like this.

class Person {
  private String name;
  private String email;

  public Person(String name, String email) {
    this.name = name;
    this.email = email;
  }

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getEmail() {
    return this.email;
  }

  public void setEmail(String email) {
    this.email = email;
  }
}

Using objects as mutable, dumb bags of data, when there are no constructions that act like bags of data provided by the language, is understandable. Sticking to this solution as the only one available in PHP, which has array literals and magic methods, is sometimes harder to justify.

Avoiding heavy builds every time we change a configuration detail and letting applications written in different languages read from the same config file is a great thing. Fortunately there's no such thing as heavy builds in the PHP world. It's quite uncommon to share all the config files with a totally different application neither. That's why associative arrays often turn out to be a faster and better solution.

I'm aware of the fact that some of the alternative solutions I presented here mean degradation of PHP tooling support (like autocomplete functions of IDEs). However, the "static vs. dynamic" conflict is a topic for another entry.

Long story short - the most important lesson I learned from working with different technologies is to always check what's the problem some solution solves before applying it.