Newcrafts 2019 Day 1

Posted on by Matthias Noback

This week I attended and spoke at the Newcrafts conference in Paris. The following is a mix of notes and personal observations I wanted to share, centered around some of the talks I saw there.

Romeu Romera: Bourdieu's Social theory and our work in tech

I had never attended a talk by Romeu before. I really enjoyed this one. Somehow I already knew that he uses a mindmap to support his talk. I thought he would use an existing mind map to navigate through the talk, but it turned out he was creating one during the talk. For me personally, a slide deck helps to keep track of the story, and it helps me remember all the different topics I need to talk about. Not so much for Romeu, who knew exactly what he was going to talk about, and didn't seem to forget to mention any important part, or make important connections.

The topic is one that seems close to his heart. Still, he called himself "not an expert", saying that this talk was an experiment. It turned out that he was hinting at the fact that the subject matter is vast, and he could only cover some parts of it during the talk. Still, the things he covered, maybe simplified a lot, were very impactful, and very interesting. I'd definitely recommend watching this talk once it becomes available online.

More than with any other talk, I think you can't help it but apply the ideas mentioned to your own situation when you listen to Romeu. He covered three parts of Bourdieu's social theory. The first part is about icons of power. The way you look and behave shows how much power you have. This modified appearance is called Symbolic Violence; an act of violance people in positions of power put onto themselves. I think in the context of conferences, being a public speaker is a great example of violence the speaker puts onto themselves. Personally, I often find it a painful experience (although I'll keep doing it as long as there's a way to help people do a better job in any way).

The second part of the theory has to do with Cultural Capital. Everyone has their own amount of cultural capital. Take for example the people in your team. Some will have more experience than others, a deeper understanding of design, architecture, etc. People with less cultural capital will be seen as lesser people. Having more cultural capital can also be an issue with speakers at a conference, where they will be automatically taken to be experts, to be better humans (or at least, better designers, programmers, etc.). They will be perceived to be more powerful, and more right. This isn't fair to either party; speakers, and attendees alike, but it's how the game gets played.

Differences in the amounts of cultural capital between people will result in Dissociation. The first thing that might happen is that you see a person with less cultural capital as someone you can ignore, not take seriously, etc. The other thing that could happen is that you'll feel that a person with more cultural capital than you is unreachable, and that they wouldn't be interested in even talking to you. Personally I can relate to this problem a lot. When I'm at a conference, it totally depends how I feel: if I feel like I have a sufficient amount of cultural capital, I'll be perfectly fine, and can speak freely with anyone in the room. If I feel that I lack cultural capital, I'm very shy, and generally tend to avoid other speakers, as I will quickly feel like an imposter, noticing a mismatch between the expected and the actual amount of cultural capital.

The third part of the theory is about Hexis, which means something like to what level you feel like you belong somewhere. Hexis could be considered "high" if you never doubt that you should be where you are now. It's low if you have doubts about your presence. Being self-condident is much appreciated, showing doubt is a signal of fragility, and it will look punishable. The immediate association I had, was how code reviews show a difference in seniority (which comes with self-confidence, never a doubt that you're in the right place). The senior developer is likely to provide a lot of nitpicking comments to the one who is more junior. The junior developer will likely have a hard time providing feedback to the senior. The situation gets worse if the senior is considered to be the boss/manager/team lead as well.

And this is where Romeu brings the discussion back to software development. The problem with some agile practices is that they assume equality in the workplace. Pair programming is easy if none of the programmers are the (perceived) boss. Retrospectives are easy if the (perceived) boss isn't there.

If you have enough cultural capital, and symbolic violence, you can ignore the problem. But if you have not, you can't. The problem is real. And of course, it's better if nobody would ignore the problem. It's also a good idea if the one with all the symbolic violence, in this case the speaker himself, doesn't provide a solution, because that solution would be made from a power position. Instead, we should all work together, so we can all feel like we belong here, like we're all equally important, like everybody can bring in their ideas.

Alberto Brandolini - The Gordian Knot

Alberto is always a joy to listen to. I found this talk very well-structured. He started out with some words about the book "Accellerate", which gives scientific support for certain practices we already considered to be best practices in our industry. One of the things so-called high-performing teams have is a short time between a commit and the release of that commit to production.

Being able to release code quickly to production requires a good culture, and that will be one of DevOps, one where there's a focus on quality, testing, and autonomy. What is culture? Alberto defines it as the accumulation of winning behavior in a group. And what is the winning behavior has a lot to do with the design of the system with which this group works. Alberto thinks it's very annoying how people ascribe a lack of quality, discipline, etc. to a mentality issue, or a culture issue that simply can't be fixed. It does seem like there are bigger issues, that can be fixed.

Daniel Pink's ideas about what motivates lead Alberto to introduce the "Pink Test" for software development teams. To be motivated, developers will need:

  1. Autonomy
  2. Mastery
  3. Purpose

After showing several examples of teams that score different results on the Pink Test, Alberto concludes that a Bounded Context (a Domain-Driven Design concept), can help you score maximally on the test, because it will be an autonomy context; one where you and your team can work mostly on your own. You can show and practice mastery within that context, and you'll be fully responsible for only this part. You can't move responsibility to another team, or other people. So, you'll be motivated to make it work well.

In order to feel purpose in your work, you still need an extra ingredient: feedback. You need to know how to get feedback, when to expect feedback. Will you hear positive feedback, or only negative feedback? Do you hear it from users, or from managers? Seeing how your software makes its users happy, is very important for a sense of purpose.

Not receiving positive feedback, can easily lead to fear of changing things, because if you break something, you'll definitely get that negative feedback. If you fix it, it will be assumed to be normal. For me personally, many, many experiences come to mind where this was the case. In fact, even if teams have celebrate-with-cake moments, they aren't really satisfying, because they usually celebrate a milestone, in terms of finished work, but not in terms of appreciated work. In my experience, celebrations don't involve users, nor focus on how the users enjoy the work that was just finished. The people in the celebration meeting may even be quietly angry about how much money it has cost them, how much still doesn't work, or how their managers are already pushing for the next thing that needs to be done.

Fear of negative feedback, but also fear of not being allowed to do something that you and your team think is necessary for your project, leads to lack of motivation. If you take a look at the Pink Test again, having to ask permission for testing means you're not very autonomous. Being dependent means that you're likely not able to perform your work in a masterful way. It robs you of purpose as well, since it's not your own boat you're sailing, it's someone else's.

Alberto gets back once more to the idea of a bounded context, and besides its function in domain modelling, points out how it's going to be really helpful in establishing a place where people can feel responsible, and experience pride in their work.

PHP Newcrafts conference Comments

Style Guide for Object Design: Release of the PHP edition

Posted on by Matthias Noback

With a foreword by Ross Tuck

Today I've released the revised edition of my latest book "Style Guide for Object Design". Over the past few weeks I've fixed many issues, smaller and larger ones. Ross Tuck and Laura Cody have read the manuscript and provided me with excellent feedback, which has helped me a lot to get the book in a better shape. I added many sections, asides, and even an extra chapter, because some topics deserve more detail and background than just a few paragraphs. Oh, and Ross wrote the kindest of forewords to kick off the book. It's available in the free sample of the book.

The book will be available at the initial "preview release" price of 20 dollars (with a suggested price of 29 dollars) but only until April 15th. Use this link to apply the discount: https://leanpub.com/object-design/c/PREVIEW_RELEASE.

What happens on April 15th?

Over the past few weeks I've been talking with some fine people from Manning, publisher of tech books. This resulted in a contract with them. They will republish the "Style Guide for Object Design". There will be an e-book, but also a printed version, which is great.

The book currently has code samples in PHP and contains some PHP-specific suggestions, but the Manning edition will have Java code samples, and no programming language or ecosystem-specific advice, hopefully making the book useful and appealing to a larger group of object-oriented programmers. This is an exciting thing for me as a book author, because I may be able to reach more people in this way.

I know that some readers prefer to read the PHP version, so that's why the version as it is now will be available until April 15th. From that moment on, you won't be able to buy it anymore. However, if you've bought the e-book from Leanpub, you will be granted access to the Manning Early Access Program (MEAP) for the book, meaning that you will eventually be able to read the Manning/Java edition too. Once this is possible, I'll send out an email to existing readers, and update the Leanpub page with instructions for joining the program.

Changelog

If you already read (part of) the book, here's a summary of the most important changes, so you can decide if it'll be useful to download and read the new version. The full change log is in the back of the book and it includes linkes to the chapters and sections that have been updated.

  • Foreword

    • Added the foreword by Ross Tuck.
  • The lifecycle of an object

    • Rewrote the explanation about the two types of objects. What really defines these types is how they are related to each other. The first type uses the second type (services versus materials).
  • Creating services

    • Added a subsection: "Keeping together configuration values that belong together", which introduces a way to keep together configuration values that belong together.
    • Added an aside: "What if I need the service and the service I retrieve from it?", which answers a common question that was asked by the technical reviewer.
  • Creating other objects

    • Added a new section: "Don't use custom exception classes for invalid argument exceptions", explaining why you don't usually need custom exception classes for invalid argument exceptions.
    • Added an aside: "Adding more object types also leads to more typing, is that really necessary?", explaining some of the benefits of using object types instead of primitive types, just in case people are wondering if all that extra typing is really necessary.
    • Added another example to the section "Don't inject dependencies, optionally pass them as method arguments", explaining how you could rewrite the currency conversion logic using a simple services. Added a comment about the design trade-offs you have to make in this type of situation.
    • Added an aside about PHP's class-based scoping, explaining how it's possible that a named constructor can manipulate private properties directly.
    • Added a subsection "Optionally use the private constructor to enforce constraints" with an example showing how you can use the private constructor when you have multiple named constructors.
    • Finish the chapter with a new section: "The exception to the rule: Data transfer objects" about Data transfer objects, a type of object with less strict rules, which was not yet discussed in detail.
  • Manipulating objects

    • Added a new introduction, explaining the different types of "other" objects and what their design characteristics are in the area of object manipulation, covering Entities, Value objects and DTOs.
    • Add an aside: "A third-party library has some object design issues, what do I do?"
  • Retrieving information

    • Added an aside: "How do you handle ambiguous naming?", explaining how you can deal with query method names that could be read as verbs (e.g. "name").
  • Dividing responsibilities

    • Added this new chapter, which elaborates on how you can make some objects be responsible for changing state, and others for providing information. It has a new, more detailed example, which is also more realistic than the current one about a player and its position.
PHP object design Comments

Hand-written service containers

Posted on by Matthias Noback

Dependency injection is very important. Dependency injection containers are too. The trouble is with the tools, that let us define services in a meta-language, and rely on conventions to work well. This extra layer requires the "ambient information" Paul speaks about in his tweet, and easily lets us make mistakes that we wouldn't make if we'd just write out the code for instantiating our services.

Please consider this article to be a thought experiment. If its conclusions are convincing to you, decide for yourself if you want to make it a coding experiment as well.

The alternative: a hand-written service container

I've been using hand-written service containers for workshop projects, and it turns out that it's very nice to work with them. A hand-written service container would look like this:

final class ServiceContainer
{
    public function finalizeInvoiceController(): FinalizeInvoiceController
    {
        return new FinalizeInvoiceController(
            new InvoiceService(
                new InvoiceRepository(
                    $this->dbConnection()
                )
            )
        );
    }

    private function dbConnection(): Connection
    {
        static $connection;

        return $connection ?: $connection = new Connection(/* ... */);
    }
}

The router/dispatcher/controller listener, or any kind of middleware you have for processing an incoming web request, could retrieve a controller from the service container, and call its main method. Simplified, the code would look this:

$serviceContainer = new ServiceContainer();

if ($request->getUri() === '/finalize-invoice') {
    return $serviceContainer->finalizeInvoiceController()->__invoke($request);
}
// and so on

We see the power of dependency injection here: the service won't have to fetch its dependencies, it will get them injected. The controller here is a so-called "entry point" for the service container, because it's a public service that can be requested from it. All the dependencies of an entry-point service (and the dependencies of its dependencies, and so on), will be private services, which can't be fetched directly from the container.

There are many things that I like about a hand-written dependency injection container. Every one of these advantages can show how many modern service containers have to reinvent features that you already have in the programming language itself.

No service ID naming conventions

For starters, service containers usually allow you to request services using a method like get(string $id). The hand-written container doesn't have such a generic service getter. This means, you don't have to think about what the ID should be of every service you want to define. You don't have to come up with arbitrary naming conventions, and you don't have to deal with inconsistent naming schemes in a legacy single project.

The name of a service is just the name of its factory method. Choosing a service name is therefore the same as choosing a method name. But since every method in your service container is going to create and return an object of a given type, why not use that type's name as the name of the method? In fact, this is what most service containers have also started doing at some point: they recommend using the name of the class you want to instantiate.

Type-safe, with full support for static analysis

Several years ago I was looking for a way to check the quality of the Symfony service definitions that I wrote in Yaml. So I created a tool for validating service definitions created with the Symfony Dependency Injection Component. It would inspect the service definitions and find out if they had the right number constructor arguments, if the class name it referenced actually existed, etc. This tool helped me catch several issues that I would only have been able to find out by clicking through the entire web application.

Instead of doing complicated and incomplete analysis after writing service definitions in Yaml (or any other meta-language for that matter), if I write them in PHP, I get all the support from static analysis tools. Even if I don't use a separate tool like PHPStan or Psalm, PhpStorm will point out any issues early on. Missing classes, missing import statements, too few or too many arguments, everything will be pointed out to me when I'm editing the ServiceContainer class in my IDE. This is a huge advantage.

Easy to refactor

Because analysis is easy, we can also expect all the help there is when refactoring our code. If we change production code, opening the ServiceContainer in your IDE will show you any issues you've produced. Furthermore, because there's no special service definition format, your IDE doesn't need a special extension to deal with it. It's just plain PHP code. So any refactoring tool that you use (e.g. rename method, move to different namespace, etc.) will also deal with any existing usages inside the ServiceContainer class.

Easy to make a distinction between public entry points and private dependencies

I like how the Symfony service container allows users to make a distinction between private and public services. Public ones can be fetched using a call to get($id), private ones can only be used as dependencies for other (public or private) services. Some services indeed deserve to be public (mostly the services we earlier called "entry points"), most should remain private. Of course, the distinction between public and private services reminds us of the way we can have public and private methods too, and in fact, if you write your own service container, you will use these method scopes to accomplish the same thing.

If you hand-write the service container you can do some optimizations too, just like the Symfony container does them. For instance, if you have a private service that's only used in one place, you can inline its instantiation. As an example, consider the private invoiceService() method:

public function finalizeInvoiceController(): FinalizeInvoiceController
{
    return new FinalizeInvoiceController(
        $this->invoiceService()
    );
}

private function invoiceService(): InvoiceService()
{
    return new InvoiceService(
        new InvoiceRepository(
            $this->dbConnection()
        )
    );
}

This method is only used by finalizeInvoiceController(), so we can safely inline it:

public function finalizeInvoiceController(): FinalizeInvoiceController
{
    return new FinalizeInvoiceController(
        new InvoiceService(
            new InvoiceRepository(
                $this->dbConnection()
            )
        )
    );
}

If, due to refactoring efforts, a private service is no longer needed, PhpStorm will tell you about it.

No need to define partial service definitions to assist auto-wiring

Auto-wiring has become quite popular, but I'm not convinced it's the way to go. I'm sure most scenarios have been covered by now, so I'm not afraid that things won't work out between me and auto-wiring. However, we'll always have to do tricks to make it work. We have to give the wirer hints about which implementations to use. This means that we may be able to delete many service definitions, but we also have to keep some around, since there are some things that won't work without them. You need to have in-depth knowledge about the dependency injection tool you use, and you need to learn the syntax for helping the auto-wirer. Worse, you may decide to adopt your production code so that the wirer can understand it.

Needless to say: if you write your service definitions in your own PHP class you'll never need custom syntax. In fact, you don't need to look up specific documentation at all, because you don't have to worry about failures to resolve dependencies; you make all the decisions yourself when you write your ServiceContainer class.

No need to inject primitive-type values by their parameter name

A downside of auto-wiring containers is that they need special instructions when the injected constructor arguments aren't objects, but primitive-type configuration values.

namespace App\Db;

final class Connection
{
    private $dsn;

    public function __construct(string $dsn)
    {
        // ...

        $this->dsn = $dsn;    
    }
}

Object-type constructor arguments can usually be resolved, but the service definition needs an extra hint for the $dsn argument:

    App\Db\Connection:
        arguments:
            $dsn: 'mysql:host=localhost;dbname=testdb'

This exposes an implementation aspect of the service class itself, which would normally remain hidden behind its public interface. To a client that instantiates an instance of Connection, only the parameter types should be relevant, not their names. In fact, a developer should be able to rename the parameter $dsn to something else, without breaking the application. Of course, a smart container builder will warn you about it when you rename a parameter, but this comes with some extra indirection that wouldn't be needed at all if we'd just write the instantiation logic inside a manual ServiceContainer class, where parameter names are irrelevant (as they should be).

No magic effects on the service container

Talking about auto-wiring, I have to say I dislike the fact that the location of a file containing a class has an influence on it being defined as a service in the container. I'd want to be able to create a new class anywhere in the project, and decide for myself whether or not it gets defined as a service. Needless to say, you won't have any magical effects like this if you write a custom service container, but personally I won't miss them.

Easier to distinguish between services and singletons

Most service containers will automatically share instances of a service; if a service has been instantiated once, the next time you ask for it, you'll get the exact same object instance. This is important for things like a database connection; you want to reuse the connection, instead of connecting to the database every time you need something from it. However, most services should be stateless anyway, and in that case it isn't really necessary to retrieve the exact same instance.

A service that's instantiated once and then shared between different clients is traditionally called a "singleton" service. Singleton services were usually implemented using the Singleton design pattern, which actually protects them from being instantiated more than once. Nowadays a service container manages service instances, and although it doesn't use the Singleton design pattern, it still makes every service effectively a singleton service: there's at most one instance of every service.

What I like about using a hand-written service container is that you can make a clear distinction between services for which it's actually important to have only one instance, and services for which it doesn't matter. Using the same example as earlier, note that the controller service can be re-instantiated every time a client needs it, and the connection service will be stored in a static variable, so that it can be reused:

final class ServiceContainer
{
    public function finalizeInvoiceController(): FinalizeInvoiceController
    {
        return new FinalizeInvoiceController(/* ... */);
    }

    private function dbConnection(): Connection
    {
        static $connection;

        return $connection ?: $connection = new Connection(/* ... */);
    }
} 

What about performance? Well, if it starts to hurt, you can always add some more shared services. But in most cases, I don't think it'll be needed. In part because of the fire-and-forget nature of the PHP server, but also because most services will be instantiated and used only once or twice anyway.

Easier to override parts for testing

With a service container based on a meta-language, like Yaml service definitions, you have to build in a mechanism for modifying the service definitions for use in different environments. With Yaml you can load in multiple service definition files and override service definitions and parameters. But just like "public" and "private" services, the concept of overriding services is also built into the programming language itself, namely by overriding methods. For example, if you want to use a fake/catch-all mailer or something while in development, you can do something like this:

abstract class ServiceContainer
{
    abstract protected function mailer(): Mailer;
}

final class DevelopmentServiceContainer extends ServiceContainer
{
    protected function mailer(): Mailer
    {
        return new FakeMailer();
    }
}

final class ProductionServiceContainer extends ServiceContainer
{
    protected function mailer(): Mailer
    {
        return new SmtpMailer(/* ... */);
    }
}

Optionally testable

If you want, you can even write an integration test for your hand-written service container. Then you could prove that the DevelopmentServiceContainer actually uses a FakeMailer. Or you can verify that all the public entry-points can be instantiated without producing any runtime errors (although static analysis will catch most of the issues already).

To be honest, this is also possible when you use a meta-language for defining services; you can always run tests against the compiled service container. However, I don't see this happening often, so I just wanted to mention the possibility here.

Composing containers? Separating containers?

A big issue with maintaining a hand-written container is that you wouldn't want to rewrite all of the framework's service definitions yourself. In fact, this isn't what I'm suggesting here. If you use a framework which ships with a service container, you just don't have to use it for your own service definitions. For instance, you can define your service container as a service in your framework's service container, and have access to it in the usual ways the framework supports.

You can even have multiple containers, for each of the modules/contexts you distinguish in your application. This could help keeping them actually separated (however, there's no technical way to enforce a context to protect the integrity of a context, it'll always be a people issue too).

Note that composition of containers is something that service containers don't usually offer, but the programming language itself is capable of. You only have to inject containers as constructor arguments of other containers.

Conclusion

In an educational setting I found that one of the biggest advantages of having your own hand-written service container for your Application and Domain layer services is that it allows you to write acceptance tests using these services. You can freely instantiate the container in your Behat FeatureContext. You can then write tests which talk to the Application layer (instead of the Infrastructure layer as they usually do). These tests will run in a very short time, but most importantly: they will be less brittle, because they don't (and can't) rely on all kinds of infrastructure-level peculiarities.

In a project setting, I haven't been fortunate enough to be able to use a hand-written service container. I'll just wait for the next opportunity to do so. If in the meantime you find yourself agreeing with the thought experiment which is this article, and have even applied the idea in practice, let me know how it worked out for you!

Finally, some suggestions for further reading:

  • Mathias Verraes has a nice explanation-in-a-gist where he argues that "We don't need no DIC libs", written after a discussion on Twitter about this topic. The gist also includes some implementation examples.
  • Marijn Huizendveld has an interesting blog post about how you can deal in a better way with environment variables (which works well with hand-written service containers too).
PHP dependency injection Comments