Telegraph: A Lambda-Style PSR-7 Middleware Dispatcher

On reflecting over the discussions surrounding the proposed PSR for HTTP middleware (on which I am coordinator), I realized there’s no reason there should *not* be a “request-only” PSR-7 middleware dispatcher.

So, here is Telegraph to fill that void.

Built over this past weekend, Telegraph is essentially a copy of Relay, which is a “request+response” middleware dispatcher. (There are a couple of minor differences.)

I also took the time to port the existing Relay middleware over to Telegraph. You can find the Telegraph middleware here.

I was asked over the weekend, “Is this a sign that the HTTP middleware proposal is moving from request+response to request-only?” (/me shrugs) I just figure if there’s such a need for something like that, perhaps it should be made available.

Oh, and I was able to quality-check and release it using Producer.

Enjoy!

Multi-Project Issue Tracking With Producer

With Producer, you can get a list of the open issues from your remote origin by running producer issues from the project repository:

$ cd ~/Code/radarphp/Radar.Adr
$ producer issues
radarphp/Radar.Adr

    14. Separate Package for ResponderAcceptsInterface?
        https://github.com/radarphp/Radar.Adr/issues/14

    29. Service level actions?
        https://github.com/radarphp/Radar.Adr/issues/29

$

However, I’m the lead on about 40 different packages and projects, and at one point or another many of them have issues to be tracked on Github. It’s tedious to go to each package repository to list its issues separately. I want to be able to see a list of all issues on all my projects; then I can review them all at once to see what gets my attention.

To get a list of all open issues on several projects, you can create a bash script that changes to each project directory and runs project issues in each one:

cd ~/Code/atlasphp/Atlas.Cli; producer issues;
cd ~/Code/atlasphp/Atlas.Orm; producer issues;
cd ~/Code/auraphp/Aura.Accept; producer issues;
; ...
cd ~/Code/radarphp/Radar.Project; producer issues;
cd ~/Code/relayphp/Relay.Relay; producer issues;
cd ~/Code/relayphp/Relay.Middleware; producer issues;

Call the script all-issues.sh, make it executable with chmod +x all-issues.sh, and then you can issue ./all-issues.sh to get a list of all open issues on all your projects. Pipe the result to a file for easy viewing if you like!

Producer 2.0.0 Released!

Just a short note to say that most (all?) of the feedback from last month’s inital release of Producer has been incorporated into today’s 2.0.0 stable release!

The major changes are:

  • You are no longer required to install Producer globally. You can now install it as a require-dev in your project and call it as ./vendor/bin/producer. (Personally, I prefer to have it global, but that’s mostly because I manage so many different libraries.)

  • Along with that, Producer now recognizes a project-specific .producer/config file so you can override Producer settings on a per-project basis.

  • Finally, Producer does not install phpunit and phpdoc any more. You will need to install them yourself, either globally or as part of your package. The benefit here is that you can now specify custom paths to phpunit and phpdoc commands in your .producer/config file.

(Producer is a command-line quality-assurance tool to validate, and then release, your PHP library package. It supports Git and Mercurial for version control, as well as Github, Gitlab, and Bitbucket for remote origins.)

PSR-7 and Session Cookies

One of the great things about PHP is its session handling capabilities. One call to session_start() and a huge amount of heavy lifting is done for you. It’s a great aid when writing page scripts.

However, as you start to need finer control over the HTTP response in your project, some of the automatic session behaviors begin to get in the way. In particular, when you are using PSR-7 to build your HTTP response, you realize that session_start() and session_regenerate_id() both automatically do the equivalent of calling setcookie() to write headers directly to the output. This means you cannot buffer those calls into the Response object for later sending.

How then can we use PHP’s session handling, when we want finer control over when and how cookies get sent?

The first trick is to tell PHP not to send a cookie when it does session work. This is accomplished with three ini_set() calls:

ini_set('session.use_trans_sid', false);
ini_set('session.use_cookies', false);
ini_set('session.use_only_cookies', true);

These direct PHP not to use transparent session IDs, not to use cookies, and (counterintuitively) to use only cookies. If I understand correctly, the combination of the last two means that PHP will read only from the cookies, and from nowhere else, to find the session ID value.

With those settings, a call to session_start() will cause PHP to read from the cookie values for the session ID, but it will not cause PHP to set any cookies for the session.

The second trick is to compare the session ID in the incoming request, to the session_id() value at the time you want to send the response. If they are different, that means a session has been started or regenerated, at which point you can send the session cookie manually. The following is an example Relay-compatible middleware that puts session cookie handling logic into effect:

SessionHeadersHandler.php

When you examine the class, note that the cookie-creation code is intended to be the same as in the PHP session handling code itself. Note also that you can extract the relevant logic (“compare the Request session ID to the current one, and send a cookie if they’re different”) and use it in a non-middleware-based application.

With SessionHeadersHandler in place, subsequent middleware decorators can call session_start() and session_regenerate_id(), and PHP will no longer automatically write out a session cookie on its own. The handler will set the cookie into a PSR-7 Response object for later sending.

Unfortunately, this is only a partial solution for session headers. The handler does not deal with things like session cache expire and limiter headers. However, it does give you control over when session cookie itself get sent, and that’s a great aid when you want to work with PSR-7 Response objects.

Producer: Validate and Release PHP Library Packages

tl;dr: Producer will look over your Composer-based library package just before you are ready to tag it for release, make sure it appears ready-to-go, and then do the release for you through Github, Gitlab, or Bitbucket. Producer works with both Git and Mercurial.

I. History

Back when I was working on Solar, we needed a process to package up each release of the entire framework and make sure I hadn’t forgotten anything. Thanks to the magic of the Internet Archive, you can see it here. You can read more about the 10 year old (!!!) process here; the script is of course PEAR-centric, since PEAR was the main packaging system available in PHP at that time.

After Solar was done, we began extracting its individual components as 30 or so separate packages in Aura. As before, I needed a process to make sure each package release was actually ready-to-go, so that earlier PEAR-centric release script evolved into a collection of Composer-centric commands. These release and management tools are specifically for Aura, with its particular conventions and expectations in mind, and have served well for 3 major versions of the project over the last 5+ years.

But now I have started some non-Aura projects: Relay, Radar, Arbiter, Bookdown, and most recently Atlas. These projects do not have the benefit of the automated release process, with all of its checks and validation, that Aura does.

With that in mind, then, I have extracted a substantial amount of the Aura package release process into a new project, Producer, so that I can use it with any non-Aura library package. That means you can use it with your library package, too.

II. Why Use Producer?

When you think your Git or Mercurial library package repository is ready for a tagged version release, Producer help to validate that it is actually in a high-quality releasable state. Then, if Producer thinks everything looks good, it will release your library package through its remote origin API (i.e., through Github, Gitlab, or Bitbucket).

(Note that Producer is not for regular daily development work. It is specifically for the day you want to release the package. At that time, it can be easy to forget steps in a release process; Producer manages those steps for you.)

III. Validating A Package For Release

Most of the things Producer checks for are there because I forgot to check them myself at some point in the past, and it was embarassing for one reason or another.

For example, you don’t want to make a release from a local copy that has not been updated to match the remote copy, or when the local copy has some modified or uncommitted files. So the very first thing Producer does is to pull down changes from the remote origin, push up local changes to the remote, and then check the local status to see if there are uncommitted files. If the local status check fails, Producer won’t release the package.

After it’s sure the local copy is in a clean state, Producer will run composer validate to make sure it has no obvious errors. Obviously, if composer.json is not valid, the package is not in a releasable state.

Next, Producer looks to see if you have a particular set of non-empty informational files in place. These are administrative, but necessary: README, LICENSE, CONTRIBUTING, and CHANGES (not CHANGELOG yet; more on that later). The files may or may not have .md extensions. These files ought to be present in any packaged release, so Producer will fail if they are not present, or if they are empty.

Of course, Producer can’t tell if their contents are sensible or not, though it can tell if the LICENSE notes the current year. If it does not, Producer will tell you to update the copyright year in the LICENSE. You don’t want to release a package with an outdated copyright year!

After that, Producer will run your test suite with PHPUnit. Producer expects that you have a phpunit.xml.dist file at the root of your package, so if that’s missing, the release will fail. Likewise, if the tests fail, Producer will not release the package.

As part of the test-running, Producer will issue composer update to make sure all the require-dev packages are in place. After the tests pass, Producer will check the local copy status yet again, to make sure the tests have cleaned up after themselves properly. This also has the benefit of checking that your “ignore” files are set up properly; at the very least, composer.lock and vendor/ should be ignored, so their presence in the status check will cause Producer to stop its release process.

We want to have well-documented code, so Producer runs PHPDocumentor to check all the docblocks in the package src/ directory. (Yes, this presumes that you have a src/ directory in your library package.) If any PHP docblocks are missing or malformed, Producer will stop the release. Similarly, if the @package tags are missing or incorrect, Producer will tell you which files and stop the release. (In this case, “correct” means “the same as the Composer package name”.)

As the next-to-last step in the validation process, Producer examines your CHANGES file commit timestamp. If the CHANGES file is not part of the very last commit, Producer will balk, and tell you to update your CHANGES so that all changes have been mentioned in the release notes. (Producer uses CHANGES because that’s what I use in Aura; at some point in the future, this may become CHANGELOG, but for now just the release-specific change listing seems enough.)

Finally, Producer will go to your remote origin API and retrieve a list of open issues for the repository. This is not technically a validation step, only a reminder in case there issues you have forgotten to address. If there are open issues, Producer will not stop the release process.

IV. Releasing A Package

The above validations can be run on their own using the producer validate command; they are useful as a pre-flight or pre-check to the actual release process. When the validate command finishes successfully, you can move on to the release command; the release process is exactly the same as the validation process, with the added step of actually releasing the package when validation passes.

At this point, Producer has already looked at your .git or .hg configuration to determine the remote origin API; this can be Github, Gitlab, or Bitbucket. It then prepares and sends a release through that API, using the CHANGES file for the release notes.

Afterwards, it will sync the local copy with the remote origin to pull down any newly-created tags.

That’s it; you’re done! Producer has now run a series of “final checks” on your repository and released it with a new version number.

V. Questions

When I announced Producer over the weekend, it got posted to Reddit by somone other than me (for once ;-). I hope I have answered the “why is Producer useful?” question with this blog post. Two others remain:

  1. Q: “Why does Producer run composer update as part of validation? It should only look at the current state of the repo, not modify the repo.”

    A: Perhaps “validation” is not the right word to use. It’s intended as a pre-flight or preparatory step towards releasing, to make sure that the package will actually install what it requires through Composer. In addition, for my own projects at least, the tests use the Composer autoloader for the src/ files, so composer update is a necessary preliminary to running the tests.

  2. Q: “Why require PHPDocumentor and PHPUnit as part of Producer? What if I have those already installed somewhere else?”

    A: For myself, global installs of these kinds of ecosystem-level tools seem reasonable, but that may be a function of the fact that I mostly manage library packages; having 30+ installs of PHPUnit and PHPDocumentor is just not to my liking. Having said that, I can see how some folks would have different requirements, so I’ll see if I can modify that requirement in a future version of Producer.

Finally, if you have questions/comments/critique, please raise them as issues over at Github. Thanks, and I hope Producer is as useful to you as its earlier versions in Aura have been to me!

Why Do PHP Developers Think MVC Is An Application Architecture?

I’ve pointed out before that Model-View-Controller is a user interface pattern, not an application architecture. But why would PHP developers get the idea that MVC is an application architecture in the first place? (This may apply to all server-side developers, not just PHP folks.)

I used to think that MVC was an application architecture. Even after reading Fowler’s POEAA and seeing that MVC was for the user interface, I figured that meant I was doing “user interface applications.” But that was not quite right; it would have been more accurate to say that I had been mixing the concerns of user interface with the underlying core application.

Based on that experience, I think the reason MVC is mistaken for an application architecture is because PHP developers generally start with page scripts. In our first page scripts, we combine all the concerns in a single ball of mud: SQL queries are intermingled with HTML, and the business logic is scattered throughout. As far as we are concerned, the page script itself is “the application.” Later, as more functionality is required, we add another page script, and another, and another. We continue to see that collection of page scripts as “the application.”

Then, as we progress in our profession, and begin to learn how to better organize our work, we start separating the different concerns of “the application.” When we begin separating concerns, we separate them out of the page script, which we see as “the application.” Extracting the view concerns from the page script means extracting them from “the application.” Separating the model from the page script into its own layer means separating it from “the application.” Pulling the controller logic out of the page script means pulling it out of “the application.” So of course Model-View-Controller is seen as an application architecture – we separated the concerns of our application according to that pattern, right?

Except, in retrospect, it’s not. One of the big leaps we have to make is to realize that MVC is for the user interface portion of our systems, just like Fowler notes. We on the server side think the user interface is HTML, CSS, and Javascript, but it’s not. Instead, the user interface is the HTTP Request and Response. In other words, the template is not the View.

Once we make that conceptual leap, we begin to realize that the Model layer is the entry point to “the application”. That is where “the application” should live, or at least where it should look like it lives. The Controller should have little to do but take input from the Request and pass it to the Model; likewise, the View should do nothing but put together the Response using the output from the Model.

With that idea of server-side MVC, we then begin to see that a lot of what’s in server-side MVC frameworks is “too much.” Framework functionality that is not related to merely taking input from a Request and presenting output through a Response becomes entirely secondary to, perhaps even actively harmful to, building well-structured applications – applications that are independent of any particular user interface.

Afterword

The server-side MVC pattern, as descended through Sun’s Model 2 architecture, is so distinctive from the client-side MVC pattern as to be a completely different thing. I realized this as I was writing my book on modernizing legacy applications, and further research led me to write up Action-Domain-Responder as a web-specific alternative to MVC. Action-Domain-Responder places a much stronger emphasis on the HTTP Request and Response as the user interface elements. If you are interested in building better applications, you may wish to read the ADR essay, and try it out in your next project.

Command Bus and Action-Domain-Responder

Over the past few weeks, different people have asked me where a Command Bus goes in an Action-Domain-Responder system. While I’m not a DDD expert, after brushing up on the subject a little, my answer is: “In the Domain.”

First, let’s recall the three components in ADR:

  • “Action” is the logic that connects the Domain and Responder. It uses the request input to interact with the Domain, and passes the Domain output to the Responder. (The Action is intentionally “dumb”: it should have no logic at all, aside from perhaps the most minimal of ternaries to allow for default input values. If the Action has a conditional, it is doing too much.)

  • “Domain” is the logic to manipulate the domain, session, application, and environment data, modifying state and persistence as needed. (The word “Domain” here is explicitly intended to remind you of “domain logic” and “domain-driven design.”)

  • “Responder” is the logic to build an HTTP response or response description. It deals with body content, templates and views, headers and cookies, status codes, and so on.

Next, let’s see what Command Bus is. There’s a lot written about it elsewhere …

… so I’ll try to sum up here:

  • A “Command” is a typed or named set of inputs (essentially a data-transfer object) that gets sent to a “Command Bus.”

  • The “Command Bus” then hands off the “Command” to a “Command Handler” specific to that “Command”; the “Command Bus” figures out which “Command Handler” to use from the name or type of the “Command.”

  • The “Command Handler” uses the “Command” inputs to perform some sort of activity.

This series of objects is part of an overarching architectural pattern called Command Query Responsibility Segregation (see here and here). Under CQRS, writes (Commands) are handled separately from reads (Queries). Handling a Command modifies data but does not return a result, while handling a Query returns a result but must not modify data.

This means that a Command Bus does not actually return a result for inspection. You dump a Command into the Bus, and you’re done; there’s no checking for errors at that time. To conform to CQRS properly, you have to perform a separate Query in order to determine the result of the Command.

At this point, just from having read the literature on the patterns and concepts, we can see that Command Bus and its related components are part of the domain layer, not part of the user interface layer. With that in mind, it seems like Command Bus is a candidate for the “Domain” portion of Action-Domain-Responder, to be used like this in an Action:

class CreateItemAction
{
    public function __construct(
        CommandBus $domain,
        CommandResponder $responder
    ) {
        $this->domain = $domain;
        $this->responder = $responder;
    }

    public function __invoke(Request $request)
    {
        $input = $request->getParsedBody();
        $command = new CreateItemCommand(
            $input['item_name'],
            $input['item_description']
        );
        $this->domain->handle($command);
        return $this->responder->createResponse();
    }
}

So the Action gets constructed with a CommandBus element as an entry point into the Domain, and with a generic Responder to build the response. At invocation time, the user interface code sends along the current HTTP request; the Action pulls data out of it to create Command to send to the Command Bus, then tells the Responder to create an HTTP response. (Because a Command never returns anything, one Responder should suffice for all Commands in this setup.)

This is straightforward as an minimal case, but I think it avoids at least two substantial issues.

  1. Where does input validation go? (Input validation, or form validation, is separate from domain model validation.)

  2. Where does error handling go? (While a Command might not return anything, the various elements related to CQRS might very well throw exceptions or raise errors.)

In what we think of as server-side MVC, those two concerns might well be placed in the Controller somewhere. Translating a Controller method directly to an Action, that might look something like this:

    public function __invoke(Request $request)
    {
        // get the input and validate it
        $input = $request->getParsedBody();
        if (! $this->validate($input)) {
            // create an "invalid input" response
            return $this->responder->invalid($input);
        }

        // create the command
        $command = new CreateItemCommand(
            $input['item_name'],
            $input['item_description']
        );

        // try the command
        try {
            $this->domain->handle($command);
            // succcess!
            return $this->responder->success();
        } catch (Exception $e) {
            // there was some sort of subsequent failure
            return $this->responder->failure($e);
        }
    }

On consideration, that seems like a lot of extraneous activity in the user interface layer. In ADR, the Action is intentionally supposed to be dumb. It should not be doing anything even remotely interesting, and certainly should not be dealing with any conditional logic.

As such, I say that Command-related activity should be taken out of the Action entirely, and relegated to something like an Application Service or some other Domain entry point. That Service is what should perform the Command-related activity.

Further, while a Command may not return a result, a Service certainly can. This means that the Action can call the Domain and get back a Domain Payload as a result, which can then be passed to the Responder for presentation.

Under that way of thinking, we get something more like this:

class CreateItemAction
{
    public function __construct(
        ItemService $domain,
        CreateItemResponder $responder
    ) {
        $this->domain = $domain;
        $this->responder = $responder;
    }

    public function __invoke(Request $request)
    {
        $input = $request->getParsedBody();
        $payload = $this->domain->create($input);
        return $this->responder->createResponse($payload);
    }
}

class ItemService
{
    public function create(array $input)
    {
        if (! $this->validate($input)) {
            // create an "invalid input" response
            return new InvalidInputPayload($input);
        }

        // create the command
        $command = new CreateItemCommand(
            $input['item_name'],
            $input['item_description']
        );

        // try the command
        try {
            $this->domain->handle($command);
            return new CommandAcceptedPayload();
        } catch (Exception $e) {
            return new CommandRejectedPayload($e);
        }
    }
}

Now the Domain is fully separated from the user interface. It can be used with both HTTP and command-line interfaces, and tested separately from them. Per the ADR pattern, the Responder becomes responsible for examining the Payload to see what kind of presentation to deliver to the client. Different Payloads result in different responses being built. Finally, the Action becomes entirely uninteresting; all of the business logic has been pushed down into the Domain, where it belongs.

So, to sum up: Command Bus is a domain layer pattern, and should be used in the Domain, not in the Action. A Command cannot return a result, but a Service can, so the entry point into the Domain is probably better as a Service that returns a Payload. This keeps the HTTP and CLI user interface logic well separated from business logic, and independently testable and reusable.

An Object Lesson in Conduct Enforcement

Full disclosure: I am acquainted with both Samantha Quinones and Matthew Trask. I have spoken at conferences with Samantha and attended her talks. Note that this post is about how codes of conduct and social expectations are selectively enforced, not about the behavior of any particular individual. If you take this post as an attack on anyone in specific then you are simultaneously “wrong” and “missing the point.”

Over the weekend, a “Concerned PHP User” wrote in to the FIG to remark on the election of Samantha Quinones as a FIG secretary:

Especially in light of the recent Code Of Conduct discussions in PHP I find this selection very disheartening. Samantha was recently outed as saying some pretty offensive things to a fellow PHP conference-goer (http://matthewtrask.net/blog/My-Time-At-SunshinePHP/). She said to this first-time conference attendee: “fuck this guy” and “you need to fuck off back to the Shire”. Matthew is short, so this was a clear insult to his height, not to mention very rude. If a code of conduct was in place in PHP as it should be I can’t help but think Samantha would have at least needed a temporary ban.

Please take these concerns into consideration. In my honest opinion, the insulting of the conference goer alone (and that just within the past month!) is enough to disqualify Samantha from this position.

(You should read Matthew Trask’s full blog post, and Samantha’s reply in the comments there.)

The replies to Concerned PHP User are universally of the form “Samantha is my friend, and I know personally she didn’t mean anything by it; this happened after the conference, so the Code of Conduct didn’t apply; and besides, she apologized, so that should be the end of it.” Here is a representative sample:

Chuck Burgess:

the comments on the linked-to post indicate they have publicly reconciled their altercation without friction.

Chris Tankersley:

looking at the blog post it seems that she immediately apologized and Matthew accepted the apology, and they both agreed to start over fresh. … I think that’s the best result you can possibly get when there is friction.

To be clear, these are all good people with good intentions. But would all these defenders of Samantha be so forgiving if a man of similar community standing had said similarly derogatory things to a woman who was a first-time conference attendee?

  • Would they not see this as somehow indicative that the man had a toxic personality, was misogynist/prejudiced/bigoted/privileged, or that the behavior was a symptom of a larger structural issue of some sort?

  • Would the apology have become a starting point (instead of an ending point) leading to further demands that the man continue to prostrate himself before the mob of public opinion?

  • Would they not have cried out that “this is what keeps women from attending conferences!” and demanded further action against the man?

  • Would there not have been concerned emails sent to the man’s employer, asking if that’s really the kind of person they wanted representing their company, one who would be so rude and dismissive to a fellow community member, especially a woman?

I opine that if the event were effectively identical, but with the sexes switched, there would be a very different discussion going on now. If the roles had been reversed, an apology would not have been sufficent. If a man of Samantha’s standing had said the exact same things to a woman who was a newcomer to the conference, there’s no way the issue would be left at that. It would be taken as yet another sign of the privilege that men have in the PHP community, that they think they can treat a woman that way. He’d have been vilified, shamed, hounded, and otherwise had his life made miserable on Twitter and elsewhere. Someone would have called his employer and asked if that was really the kind of person they want representing their company.

To be clear, I am not calling for Samantha to be fired, denied a position, or otherwise have her life made miserable. I am pointing out that allowances are being made based on who the offender and offended are.

This goes back to something I’ve been saying about Social-Justice-derived Codes of Conduct in general, and the proposed Code of Conduct for PHP in specific, for a long time now: the “rules” apply differently to different people, especially depending on who is doing the enforcing. Some rule-breakers will be forgiven their transgressions, and others will be prosecuted as much as possible, merely by fact of who they are and what they represent. My shorthand for that attitude is “That’s just Joe being Joe!” – Joe’s actions, when performed by George, will result in banishment for George and forgiveness for Joe. There’s always some reason that Joe can be forgiven that will never apply to George.

So either you are in favor of all people treating others with equal respect and dignity at all times, under a Code of Conduct or otherwise, or you are in favor of some people being more equal than others and being given allowances based on who they are and what narrative they fit. If you would have punished a man for Samantha’s behavior, you should punish Samantha too; if you do not punish Samantha for her behavior this time, you should not punish anyone else in the future for any behavior resembling hers.


Finally, a side note. One commenter in the PHP-FIG thread opined: “If a code of conduct was in place, for PHP internals, then that code of conduct would have no bearing here. It is entirely a different organisation.”

There is plenty of reason to believe that it would apply here, and at any time PHP community members gather together or speak with each other, regardless of location or channel.

Further, if PHP as-a-project ever adopts a Code of Conduct, that code will metastasize (through voluntary action or otherwise) across the entire PHP community. PHP user groups, projects, conferences, etc., will adopt it merely because it is “The PHP Code Of Conduct.”

So don’t believe for a moment that a PHP-project-level Code of Conduct won’t be applied to you in some fashion. It will. Prepare yourself accordingly, and speak out against it if you can.

UPDATE: Some quotes removed at the request of the quoted persons, who have since deleted their comments on the FIG thread.

You Do Not Have A Right To Contribute

(Another in a series on the proposed PHP code of conduct, itself a work in progress in at least one other place.)

Over the weekend I listened to a recent episode of the Dev Hell podcast, hosted by Chris @grmpyprogrammer Hartjes and Ed @funkatron Finkler, and guest-starring Amanda @AmbassadorAwsum Folson. (Full disclosure: I have been a guest on the podcast previously.)

The episode is #70 “Anti-Canuckite Leanings”, and in it, they discuss the proposed code of conduct starting around 26:00. You should listen to the whole discussion, which ends after about 30 minutes (and really the whole episode if you can).

There’s a lot to address in the discussion, but I’m going to concentrate on only one point. Chris Hartjes says, at about the 30:17 mark:

I think fighting against the code of conduct is a losing battle, because it will get passed. And you have a choice, you can either keep contributing to PHP, or move on and do something else. It’s as simple as that. You do not have a right to contribute to PHP, it’s a privilege. It sucks how that privilege is handed out, and it sucks how sometimes that privilege is wielded as a stick by which to beat other poeople, but at the end of the day, despite it being an open source project, it is a private project, and nobody has to take your contributions. It’s as simple as that.

He reiterates the point a few times:

(48:09) If you don’t like it, go on and contribute to another project.

(48:44) The people who complain, well they either get with the program, or they just go do something else with their time.

(51:45) If you don’t like it, just don’t participate in the project.

To be sure, Chris does not specifically say he is either for or against the code of conduct as presented in the RFC, which currently uses the language of the Contributor Covenant.

Even so, I have heard variations of this from Contributor Covenant supporters. These kinds of comments strike me as interesting in two ways.

First, “If you don’t like it, just don’t participate in the project” and its variations do not seem in the spirit of “fostering an open and welcoming community.” I see this as revealing part of the true intent of Contributor Covenant supporters: to wit, they wish to set themselves up as judges of who is to be accepted, and who is to be rejected.

Second, and more importantly, the very same argument applies in favor of the status quo; that is, not having an explicit code of conduct. Let’s take a look at the same wording, but against having a code of conduct:

If the project does not have a code of conduct, you have a choice, you can either keep contributing, or move on and do something else. It’s as simple as that. You do not have a right to contribute, it’s a privilege. At the end of the day, despite it being an open source project, it is a private project, and nobody has to take your contributions. It’s as simple as that.

So the argument is simultaneously made for not-having a code of conduct, using exactly the same wording. If you don’t like that there’s no code of conduct, “go on and contribute to another project.” After all, “you do not have a right to contribute.” You can “either get with the program, or just go do something else with your time.”

This means to me, among other things, that the burden of proof remains on those who support the Contrbutor Covenant, proof which they sorely lack, or are unwilling to put forth.

For the record, this is not an attempt to hammer on Chris, whom I count as a friend. It is an attempt only to point out one of the many flawed arguments of some who support the Contributor Covenant.

Finally, for the record, I continue to be opposed to the Contributor Covenant and anything substantially similar to or derived from it. Having no code of conduct is better than having the Contributor Covenant.

On the Proposed PHP Code of Conduct

Recently, Anthony Ferrara opened an RFC for PHP internals to adopt and enforce a code of conduct. Even leaving aside for the moment whether this is an appropriate use of the RFC system, the RFC generated a lot of discussion on the mailing list, in which I participated at great length, and for which I was hailed as abusive by at least one person in favor of the RFC (a great example of a kafkatrap).

To restate what I said on the mailing list, my position on the RFC is not merely “opposed”, but “reject entirely as unsalvageable” (though I did make some attempts at salvage in case it goes through). I continue to stand by everything I said there, and in other channels, regarding the proposed Code of Conduct.

Normally, if you had not heard about this particular discussion, I would say you were lucky, and probably the happier for it. In this case, I have to say that you should be paying close attention. The Code of Conduct as presented enables its enforcers to stand in judgment of every aspect of your public, private, professional, and political expression. I understand that’s a bold assertion; I will attempt to support it below.

The Contributor Covenant version on which the RFC is based is authored and maintained by intersectional technologist and transgender feminist Coraline Ada Ehmke. Ehmke believes that open source is a political movement:

From the onset open source has been inherently a political movement, a reaction against the socially damaging, anti-competitive motivations of governments and corporations. It began as a campaign for social liberty and digital freedom, a celebration of the success of communal efforts in the face of rampant capitalism. What is this if not a political movement?

Why Hackers Must Welcome Social Justice Advocates

Whether or not this description of open source is accurate, it is true that Ehmke thinks of open source as a political arena. As such, one must read the Contributor Covenant as a political document, with political means and political ends. Specifically, it is a tool for Social Justice.

As a tool for Social Justice, it recognizes no boundaries between project, person, and politics. This attitude is written into the Contributor Covenant with the text, “This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.” So, when is a project participant not representing the project? The answer appears to be “never.”

That is, a project participant is always representative of the project. We can see one example of this from the “Opalgate” incident. In reference to a Twitter conversation where Opal is not the subject, Ehmke opens an Opal project issue, and then attempts (with a Social Justice mob of backers) to intimidate the project managers into removing one of the Twitter conversants from the project because of his non-project-related speech.

This is Social Justice in action. Remember, it is the author of the Contributor Covenant acting this way. To look at this incident, and simultaneously opine that the Covenant as a tool of Social Justice is somehow not political, or that it does not intend to police speech unrelated to the project, reveals that opinion as obviously incorrect. This kind of behavior is not “abuse” of the Contributor Covenant; it is the intended application of the Covenant. The Covenant is designed specifically to enable that behavior under cover of “safety” and “welcoming” and “respect”.

But “safety” and “welcoming” and “respect” are the primary goals of the Covenant, aren’t they? I assert they are the curtain behind which the true goal is veiled: power over persons who are not sufficiently supportive of Social Justice. I think is it appropriate to mention the motte and bailey doctrine here:

[The doctrine is compared] to a form of medieval castle, where there would be a field of desirable and economically productive land called a bailey, and a big ugly tower in the middle called the motte. If you were a medieval lord, you would do most of your economic activity in the bailey and get rich. If an enemy approached, you would retreat to the motte and rain down arrows on the enemy until they gave up and went away. Then you would go back to the bailey, which is the place you wanted to be all along.

So the motte-and-bailey doctrine is when you make a bold, controversial statement. Then when somebody challenges you, you claim you were just making an obvious, uncontroversial statement, so you are clearly right and they are silly for challenging you. Then when the argument is over you go back to making the bold, controversial statement.

Sentiments like “safety” and “welcoming” and “respect” are the motte of the Covenant: the defensible tower from which challengers are ridiculed. (“It’s nice! Who doesn’t want to be nice? Why do you think we should enable harassers and abusers? Why do you want to exclude women, LGBTQ, etc?”) But the real purpose of the Covenant is to enable work in the bailey: that is, to gain power over the political enemies of Social Justice, by using project membership as a form of leverage over them.

We saw that bailey-work in the Opalgate example above. As another example of attempting to use leverage, we have the following incident in the Awesome-Django project, run by Roberto Rosario. Rosario turned down a pull request, and thereafter received this demand to adopt and enforce the Contributor Convenant. (Interestingly enough, Github deleted the issue entirely, as far as I know without comment, and without notification to Rosario; the archive.is link appears to be the only evidence of the issue’s existence.)

After Rosario declined, the issue-opener ended the conversation with an attempt at intimidation: “You are a member of the Django Software Foundation and are supposed to be setting the example. I will be forwarding the content of this issue to the Chair to evaluate your continued presence in the DSF.”

Thus, the issue-opener began in the motte (“welcoming” and “respect”) but ended on the bailey (threats to leverage refusal of the Covenant into rejection from a project). Again, this is not an abuse of the Covenant. As a tool of Social Justice, that is its author’s intended purpose: to give cover for threats and intimdation against those who do not support the author’s politics.

Since threats and intimidation are the end-game, consider what else might be threatened by being insufficiently supportive of Social Justice in general, and the Contributor Covenant in specific. Any project leader, any conference organizer, any publisher, or any employer, might be approached regarding your politically-incorrect opinions as expressed on any non-project forum or subject, and be threatened and intimidated into distancing themselves from you. This leads to ejection from projects, denial or disinvitation from conferences, rejection of manuscripts, and refusal-to-hire or outright firing, based on political (not professional) concerns.

This is not the kind of behavior found in a free and open society. It is instead the behavior of a society that is totalitarian, even fascist-with-a-smiley-face. You are not allowed to disagree with the Social Justice proponents, in any capacity. You are not even allowed to “not care” – you will be made to care.

As such, I assert that the Contributor Covenant, and any other codes of conduct originating in Social Justice, are to be opposed out of hand, both in PHP, and in any other place they are suggested.

Postscript

While reading in preparation for writing this piece, I came across a lot of information that didn’t really fit, but might still be useful. Here’s a partial list of links.

Social Justice In Action

Discussions About Codes of Conduct

Alternative Codes of Conduct