Remote working
Recently I read Ouarzy’s review of Jason Fried and David Heinemeier Hansson’s “Remote - Office Not Required”. I’d read their previous books, “Getting Real” and “Rework”. They’re all a joy to read. Short chapters, nice little cartoons. Just a lot of fun, and inspiring too. Not many authors make as much of an effort as they do to condense their message and reward the reader for taking the time to read an actual book. It’s insulting how much work some authors expect you to put in before they will reveal their secrets!
Context passing
I’m working on another “multi-tenant” PHP web application project and I noticed an interesting series of events. It felt like a natural progression and by means of a bit of dangerous induction, I’m posing the hypothesis that this is how things are just bound to happen in such projects.
In the beginning we start out with a framework that has some authentication functionality built-in. We can get the “current user” from the session, or from some other session-based object. We’ll also need the “current company” (or the “current organization”) of which the current user is a member.
Combing legacy code string by string
I find it very curious that legacy (PHP) code often has the following characteristics:
- Classes with the name of a central domain concept have grown too large.
- Methods in these classes have become very generic.
Classes grow too large
I think the following happened:
The original developers tried to capture the domain logic in these classes. They implemented it based on what they knew at the time. Other developers, who worked on the code later, had to implement new features, or modify domain logic, because, well, things change. Also, because we need more things.
Exceptions and talking back to the user
Exceptions - for exceptional situations?
From the Domain-Driven Design movement we’ve learned to go somewhat back to the roots of object-oriented design. Designing domain objects is all about offering meaningful behavior and insights through a carefully designed API. We know now that domain objects with setters for every attribute will allow for the objects to be in an inconsistent state. By removing setters and replacing them with methods which only modify the object’s state in valid ways, we can protect an object from violating domain invariants.
Mocking the network
In this series, we’ve discussed several topics already. We talked about persistence and time, the filesystem and randomness. The conclusion for all these areas: whenever you want to “mock” these things, you may look for a solution at the level of programming tools used (use database or filesystem abstraction library, replace built-in PHP functions, etc.). But the better solution is always: add your own abstraction. Start by introducing your own interface (including custom return types), which describes exactly what you need. Then mock this interface freely in your application. But also provide an implementation for it, which uses “the real thing”, and write an integration test for just this class.
Modelling quantities - an exercise in designing value objects
I recently came across two interesting methods that were part of a bigger class that I had to redesign:
class OrderLine
{
/**
* @var float
*/
private $quantityOrdered;
// ...
/**
* @param float $quantity
*/
public function processDelivery($quantity)
{
$this->quantityDelivered += $quantity;
$this->quantityOpen = $this->quantityOrdered - $quantity;
if ($this->quantityOpen < 0) {
$this->quantityOpen = 0;
}
}
/**
* @param float $quantity
*/
public function undoDelivery($quantity)
{
$this->quantityDelivered -= $quantity;
if ($this->quantityDelivered < 0) {
$this->quantityDelivered = 0;
}
$this->quantityOpen += $quantity;
if ($this->quantityOpen > $this->quantityOrdered) {
$this->quantityOpen = $this->quantityOrdered;
}
}
}
Of course, I’ve already cleaned up the code here to allow you to better understand it.
ORMless; a Memento-like pattern for object persistence
Something that always bothers me: persistence (the user interface too, but that’s a different topic ;)). Having objects in memory is nice, but when the application shuts down (and for PHP this is after every request-response cycle), you have to persist them somehow. By the way, I think we’ve all forever been annoyed by persistence, since there’s an awful lot of software solutions related to object persistence: different types of databases, different types of ORMs, etc.
Defining multiple similar services with Docker Compose
For my new workshop - “Building Autonomous Services” - I needed to define several Docker containers/services with more or less the same setup:
- A PHP-FPM process for running the service’s PHP code.
- An Nginx process for serving static and dynamic requests (using the PHP-FPM process as backend).
To route requests properly, every Nginx service would have its own hostvcname. I didn’t want to do complicated things with ports though - the Nginx services should all listen to port 80. However, on the host machine, only one service can listen on port 80. This is where reverse HTTP proxy Traefik did a good job: it is the only service listening on the host on port 80, and it forwards requests to the right service based on the host name from the request.
Mocking at architectural boundaries: the filesystem and randomness
In a previous article, we discussed “persistence” and “time” as boundary concepts that need mocking by means of dependency inversion: define your own interface, then provide an implementation for it. There were three other topics left to cover: the filesystem, the network and randomness.
Mocking the filesystem
We already covered “persistence”, but only in the sense that we sometimes need a way to make in-memory objects persistent. After a restart of the application we should be able to bring back those objects and continue to use them as if nothing happened.
Lasagna code - too many layers?
I read this tweet:
"The object-oriented version of spaghetti code is, of course, 'lasagna code'. Too many layers." - Roberto Waltman
— Programming Wisdom (@CodeWisdom) February 24, 2018
Jokes taken as advice
It’s not the first time I’d heard of this quote. Somehow it annoys me, not just this one joke, but many jokes like this one. I know I should be laughing, but I’m always worried about jokes like this going to be interpreted as advice, in its most extreme form. E.g. the advice distilled from this tweet could be: “Layers? Don’t go there. Before you know it, you have lasagna code…”