Woke, Progressive, Left: It's All Marxism

Anti-Marxist liberals have labored under numerous disadvantages in the recent struggles to maintain control of liberal organizations. One is that they are often not confident they can use the term “Marxist” in good faith to describe those seeking to overthrow them. This is because their tormentors do not follow the precedent of the Communist Party, the Nazis, and various other political movements that branded themselves using a particular party name and issued an explicit manifesto to define it. Instead, they disorient their opponents by referring to their beliefs with a shifting vocabulary of terms, including “the Left,” “Progressivism,” “Social Justice,” “Anti-Racism,” “Anti-Fascism,” “Black Lives Matter,” “Critical Race Theory,” “Identity Politics,” “Political Correctness,” “Wokeness,” and more. When liberals try to use these terms they often find themselves deplored for not using them correctly, and this itself becomes a weapon in the hands of those who wish to humiliate and ultimately destroy them.

The best way to escape this trap is to recognize the movement presently seeking to overthrow liberalism for what it is: an updated version of Marxism. I do not say this to disparage anyone. I say this because it is true. And because recognizing this truth will help us understand what we are facing.

The new Marxists do not use the technical jargon that was devised by 19th-century Communists. They don’t talk about the bourgeoisie, proletariat, class struggle, alienation of labor, commodity fetishism, and the rest, and in fact they have developed their own jargon tailored to present circumstances in America, Britain, and elsewhere. Nevertheless, their politics are based on Marx’s framework for critiquing liberalism (what Marx calls the “ideology of the bourgeoisie”) and overthrowing it.

Via https://quillette.com/2020/08/16/the-challenge-of-marxism/. Read the whole thing, especially for the "framework of Marxism."

What Is Good Code?

(Epistemic status: I am not entirely satisfied with the Merchant here, but it's the closest I've been able to get so far.)


When managing developers, and when watching conversations between developers online, I sometimes notice them arguing past each other about what constitutes "good code". One group will assert that good code must adhere to specific programming practices. The other will assert that good code is code that makes money for its author.

In the worst cases, each camp derides the other. The first camp will say the other is immature and inexperienced, begging for trouble; the second camp that the other are mindless slaves to old dogmatism, and want everyone else in their chains. The first will say the other is dangerously unprofessional; the second will reply "Don't care: shipping and billing!"

In the course of trying to work through the arguments on each side, so that I can explain them to myself and others, I have started using the names "Priest" and "Merchant" as categories to help give me a handle on the attitudes expressed.

While the following descriptions are necessarily caricatures, I think they capture some recognizable qualities of the Priest and Merchant: what they care about most, their goals and focus, their time preferences, and their blind spots. In each case we start with the question, "What is good code?"

The Priest

When you ask the Priest "what is good code?", his answers will have this flavor:

  • Good code is SOLID.

  • Good code is well-abstracted and well-encapsulated.

  • Good code is well-separated into appropriate layers and concerns.

  • Good code is cleanly organized and architected.

  • Good code has tests -- especially unit tests.

There are similar variations on these answers; they reveal that the Priest is program oriented. He cares first and foremost about the code for its own sake.

The overarching goal of the Priest is holiness -- sometimes known as "code quality," or "correctness," or "conformance to standards."

The Priest is focused on peer satisfaction -- that is, on the satisfaction of other Priests who review his code. It is other Priests who will determine how well he has achieved holiness in his code.

The Priest has a preference for the long-term time horizon. He is driven to make working with his code frustration-free for the many years he expects it to exist.

One problem with the Priest-like desire for holiness in code, is that it leads into holiness spirals. Priests engage in arguments about whether sufficient code holiness has been achieved -- and of course, the answer is always that the code is not holy enough.

Each Priest, to demonstrate his own holiness, is eager to point out how his code is holier than yours, and to explain how yours could become even holier than it is. There is always a way for your code to be more SOLID. There are ever more finely-tuned abstractions to implement. The testability, and the tests themselves, can always be improved. The spiral towards more-perfected holiness never ends.

The Priest recognizes no boundary or limiting principle to coding for holiness -- why would a Priest ever volunteer to be less holy than possible?

The Merchant

When you ask the Merchant "what is good code?", his answers will have a different flavor:

  • Good code is code that makes money -- the sooner, the better!

This answer, and its variations, reveal that the Merchant is product-oriented. He cares first and foremost about the product being marketed, not about the code behind the product.

The overarching goal of the Merchant is market success -- whether in financial terms, or in terms of beating out competitors.

The Merchant is focused on customer satisfaction -- that is, the satisfaction of people who use the product, and do not ncessarily care about how the code behind the product operates. It is the customers who will determine the market success of his product.

The Merchant has a preference for the near-term time horizon. He is concerned with shipping code sooner rather than later, so that the product can achieve market success more quickly, and so that product iterations through the market are more responsive. Every minute of coding effort that does not line up directly with market success through customer satisfaction is a minute of coding effort to be avoided.

One problem with the Merchant-like desire for quick market success is that it leads quickly to technical debt. Speed in getting product to market means that little attention is paid to longer-term program concerns, which makes the product more difficult to improve over time. The codebase becomes resistant to change, which means the product cannot respond quickly to changed conditions for market success. This means living with the product and the pain it produces, abandoning the product and moving on to another one, or rewriting it entirely -- again, as quickly as possible.

The Merchant recognizes no boundary or limiting principle to coding for market success -- why would a Merchant ever volunteer for less market success than possible?

Which Is Better?

This is the old program-vs-product dichotomy again. In some ways it represents an argument about primacy: which mode is to dominate the other, the Priest-like or the Merchant-like?

The program-oriented developer (the Priest) wants a good codebase on which the product is founded. The product-oriented developer (the Merchant) wants a good product to present to the market.

But which approach is the right one? Or at least, which one is more pragmatic than the other -- which is the more practical approach?

Both the Priest and the Merchant will defend their attitude as being "practical." However, to quote Rand: "What is 'practical' depends on what you want to practice."

Obviously, says the Priest, coding for the long-term is practical. It helps to keep the codebase lower-cost in the end, even if it takes longer to ship to production. The venture will be better for it over all.

And obviously, says the Merchant, coding for the near-term is practical. The longer it takes to get the product to market, the longer it takes for the venture to succeed. There won't be a long-term if we don't make it through the near-term.

The Priest is OK with shipping later, to avoid foreseeable technical debt in advance, since avoiding technical debt is clearly a practical approach.

The Merchant is eager to ship sooner, and deal only with actually-realized technical debt later, since achieving market success earlier is clearly a practical approach.

The Priest wants to "do things the right way" to satisfy other Priests. The Merchant wants to "do things the right way" to satisfy the market.

The Priest will try to argue for excellence in the program according to various quality measures. The Merchant will argue that mass appeal in the market is itself a form of excellence in the product.

For just about any variation of these kinds of arguments, both the Priest and the Merchant have strong but conflicting cases.

Resolving The Conflict

What occurs to me is that both of these attitudes or aspects are simultaneously present in developers. The difference is not that one attitude or the other is present or absent, but that one aspect or the other is emphasized or de-emphasized by each developer to a different extent.

Stated differently: it is not that a developer is a Priest or a Merchant. It is that each developer emphasizes the Priest-like and Merchant-like aspects of his approach to different levels.

One developer may give the vast majority of emphasis to his Priest-like desires. Conversely, another will much more strongly emphasize the Merchant-like aspects of his personality. Even so, every Priest exhibits some Merchant behaviors once in a while, and every Merchant acts like a Priest sometimes. This is because doing so 100% either way leads to trouble.

On the Merchant side, if it's all product all the time, you end up with a program that is a mess, and the product cannot continue -- at least, not without greatly increased frustration and pain while working with the code.

On the Priest side, if it's all program all the time, you never get a product to market -- or at least, it takes more time than you have available, and the codebase is discarded when the venture fails.

A Priest-only developer would never ship a product, because the program can never be holy enough. A Merchant-only program would be entirely unreadable by others, since the program behind a successful product need not conform to the expectations of other developers.

Yet the Priest ships code to market (though perhaps not as early as the Merchant), and Merchant code conforms to expectations (though perhaps not as well as that from the Priest).

So it must be that every developer possesses at least some amount of each aspect. This means the two aspects are each in tension with each other. And whereas neither of the two aspects has a limiting principle of its own, each aspect can act as a limit on the other.

As an exercise, try to see which of those aspects you emphasize more strongly. Then, consciously practice consulting the other aspect -- in doing so, you may be able to more effectively evaluate tradeoffs when deciding when code is not yet holy enough, or for when it would be better to ship now and deal with technical debt later.

Then the Merchant aspect might be able to accept some more non-product efforts for the sake of the program. And the Priest aspect might be able to accept some more unholiness in the program for the sake of the product.

Afterword

The "quality of product versus quality of program" topic looks like a running theme with me; here are some other posts on the subject.

Payload-Interop 1.0.0 Released

I am happy to announce that after one change from its public review period, the payload-interop specification has been released as 1.0.0 stable!

From the README:

The Domain Payload Object pattern was first described by Vaughn Vernon at https://vaughnvernon.co/?page_id=40

Whereas a Data Transfer Object provides properties found on domain objects, a Domain Payload Object provides entire domain objects. Its purpose is to transport those domain objects across the architectural boundary from the domain layer to the user interface layer.

The Domain Payload Object is not for intra-domain use. It is only for transporting a domain result across the domain layer boundary back to the calling code, typically the user interface layer.

Further, the Domain Payload Object is independent of any particular user interface. As part of the domain layer, it should have no knowledge of HTTP or CLI contexts.

This project defines only a reading interface, so that any user interface code can know how to get both the result and the status out of the Domain Payload Object.

This project does not define a writing or mutation interface. Creation and manipulation of Domain Payload Objects are core application concerns, not user interface concerns. The domain-specific nature places it outside the scope of an interoperability specification.

Try it out on your next project!

No, Jesus Was Not A Socialist

Christians are commanded in Scripture to love, to pray, to be kind, to serve, to forgive, to be truthful, to worship the one God, to learn and grow in both spirit and character. All of those things are very personal. They require no politicians, police, bureaucrats, political parties, or programs.

“The poor you will always have with you, and you can help them any time you want,” says Jesus in Matthew 26:11 and Mark 14:7. The key words there are you can help and want to help. He didn’t say, “We’re going to make you help whether you like it or not.”

In Luke 12:13-15, Jesus is approached with a redistribution request. “Master, speak to my brother that he divideth the inheritance with me,” a man asks. Jesus replied, “Man, who made me a judge or divider over you?” Then he rebuked the petitioner for his envy.

Christianity is not about passing the buck to the government when it comes to relieving the plight of the poor. Caring for them, which means helping them overcome it, not paying them to stay poor or making them dependent upon the state, has been an essential fact in the life of a true Christian for 2,000 years. Christian charity, being voluntary and heartfelt, is utterly distinct from the compulsory, impersonal mandates of the state.

Via https://www.washingtonexaminer.com/opinion/no-jesus-was-not-a-socialist.

Implicit Bias Is Pseudo-Scientific Nonsense

Via Ted Frank we have this:

The implicit association test ... is an excellent example [of the replication crisis in social "science"]. Banaji and Greenwald claim that the IAT, a brief exercise in which one sits down at a computer and responds to various stimuli, measures unconscious bias and therefore real-world behavior. If you score highly on a so-called black-white IAT, for example, that suggests you will act in a more biased manner toward a black person than a white person. Many social psychologists view the IAT, which you can take on Harvard University’s website, as a revolutionary achievement, and in the 20 years since its introduction it has become both the focal point of an entire subfield of research and a mainstay of diversity trainings all over the country. That’s partly because Banaji, Greenwald, and the test’s other proponents have made a series of outsize claims about its importance for fighting racism and inequality.

The problem, as I showed in a lengthy rundown of the many, many problems with the test published this past January, is that there’s very little evidence to support that claim that the IAT meaningfully predicts anything. In fact, the test is riddled with statistical problems — problems severe enough that it’s fair to ask whether it is effectively “misdiagnosing” the millions of people who have taken it, the vast majority of whom are likely unaware of its very serious shortcomings. There’s now solid research published in a top journal strongly suggesting the test cannot even meaningfully predict individual behavior. And if the test can’t predict individual behavior, it’s unclear exactly what it does do or why it should be the center of so many conversations and programs geared at fighting racism.

From https://nymag.com/intelligencer/2017/12/iat-behavior-problem.html.

Payload-Interop Public Review Period

The payload-interop project defines an interoperable interface for reading the domain result and domain status from a Domain Payload Object, whose purpose is to transport domain objects across the architectural boundary from the domain layer to the user interface layer.

After a long incubation period and much research, the project has finished internal deliberation and is now inviting wider public review. You can go straight to the code here.

Please send your comments, questions, and critiques as Github issues. Pull requests are also welcome.

Thanks, and happy New Year!

Atlas, PostgreSQL, and RETURNING

One of the powerful features of PostgreSQL is its RETURNING clause. For example, if you have a table like this ...

CREATE TABLE articles (
    article_id SERIAL PRIMARY KEY,
    title      VARCHAR(255) NOT NULL,
    -- ...
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

... and you insert a row using Atlas.Query with a RETURNING clause ...

/** @var $insert \Atlas\Query\Insert */
$insert
    ->into('articles')
    ->columns(['title' => 'My Article'])
    ->returning('created_at');

$pdoStatement = $insert->perform();

... then you can fetch the RETURNING column values from the PDOStatement result:

$returning = $pdoStatement->fetch(PDO::FETCH_ASSOC);
var_export($returning);
// ['created_at' => (the postgresql timestamp)]

If you have an Atlas.Table data gateway for that table, you can make use of RETURNING in your TableEvents classes to populate database-provided values into your Row objects automatically.

To do so, add a RETURNING clause in the modifyInsertRow() method, then retrieve the values into the Row in the afterInsertRow() method:

// ...

class ArticleTableEvents extends TableEvents
{
    public function modifyInsertRow(
        Table $table,
        Row $row,
        Insert $insert
    ) : void
    {
        $insert->returning('created_at');
    }

    public function afterInsertRow(
        Table $table,
        Row $row,
        Insert $insert,
        PDOStatement $pdoStatement
    ) : void
    {
        $returning = $pdoStatement->fetch(PDO::FETCH_ASSOC);
        $row->created_at = $returning['created_at'];
    }
}

Now when a Row gets inserted through the Table data gateway, the created_at value will be populated automatically.

/** @var $tableLocator \Atlas\Table\TableLocator */
$articleTable = $tableLocator->get(ArticleTable::CLASS);
$article = $articlesTable->newRow();
$article->title = 'bar';
$articleTable->insertRow($article);
echo $article->created_at; // the postgresql timestamp

You can do the same for updates as well, using modifyUpdateRow() and afterUpdateRow().

Bonus: becuase it uses both Atlas.Table and Atlas.Query, this functionality is available "for free" in Atlas.Orm!

Controllers are Services

tl;dr: Contra my previous opinion, controllers are Service objects; my understanding of a "Service", regarding DI/SL Containers, was incorrect. However, I do continue to opine that it is better use a Factory to get new Controller instances, rather than getting them from the Container directly in a non-Factory object. All that and more in this followup post.


I

My previous post generated a great discussion on Reddit between myself and /u/ahundiak, which I suggest you read in its entirety. To summarize:

  • I thought of Services in a Container as objects that are retained for reuse throughout the application; e.g. a PDO instance, a logger, etc.

  • ahundiak disagreed, and pointed to the Symfony explanation of a Service as "objects that do something", even when not shared throughout the system.

  • I found that explanation unsatisfying and not well-defined.

  • However, ahundiak also said "Symfony only creates service definitions for objects which are actually injected somewhere." That piqued my interest, because it got closer to the heart what I was trying to express.

From there we ventured a bit further afield.

II

Based on that conversation, I did a couple hours' of research, using variations on "what is a service object" (and you get some unexpected search results in a couple of cases). In the end, though, I found myself at the Misko Hevery article To new or not to new.

I have taken Misko's advice before, particularly from his article on How to Think About the “new” Operator with Respect to Unit Testing; I believe I refer to it in MLAPHP. In that article, his final summary point is that your classes should either have application logic in them, or have new operators, but not both.

The idea is that object construction is a concern to be separated from object use. The end result is that you put all object construction into Factories, and anything that needs to create an object uses the Factory instead of the new operator.

In his later article on "To new or not", Misko lays out definitions around two distinct groups of objects within any application. Lightly edited for comprehension and emphasis, he says:

  • "Injectables" are objects which you will ask for in the constructors and expect the DI framework to supply. ... All external services are Injectables. ... Sometimes I refer to Injectables as Service Objects, but that term is overloaded.

  • There are a lot of objects out there which DI framework will never be able to supply. Let's call these “Newables” since you will be forced to call new on them manually. ... Newables are objects which are at the end of your application object graph. ... Sometimes I refer to Newables as Value Object, but again, the term is overloaded.

  • It is OK for Newable to know about Injectable. What is not OK is for the Newable to have a field reference to Injectable.

Now that is something I can wrap my head around. To a first approximation, Newables/Values are leafs on the object graph; everything else on the path to a Newable/Value is an Injectable/Service.

I think that very nicely backs up ahundiak's reference to Symfony's explanation about Service objects, with some additional and welcome rigor.

Misko goes on to define some rules-of-thumb around Injectables/Services and Newables/Values. Paraphrasing and summarizing:

  • An Injectable can ask for primitives (int, float, string, etc.) and other Injectables in its constructor, but never a Newable.

  • Conversely, a Newable can ask for primitives and other Newables in its constructor, but never an Injectable.

III

Based on Misko's definition (which is obviously better than my prior one) Controllers are Services that a DI container can provide. Mea culpa.

However, I continue to stand by a corollary opinion I expressed in the previous article: that you should not retain a Controller instance for reuse inside the Container. Instead, you should use a Factory to create the Controller instance. Further (and I did not say this explicitly) you should typehint on that Factory instead of the Container itself.

Now, it is well within the proper scope of a Container to be used as a Factory. A Container plays two roles: that of Factory (to create new object instances) and of Registry (to retain already-created instances for shared use). So in a Dispatcher, for example, you could do this to run a Controller based on Route information:

class Dispatcher
{
    protected $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function dispatch(Route $route)
    {
        $class = 'App\Http\Controller\\' . $route->getController();
        $object = $this->container->new($class);
        $method = $route->getAction();
        $params = $route->getParams();
        return $object->$method(...$params);
    }
}

That's not bad -- by calling new() on the Container, you can tell the Container is being used as a Factory, not a Registry. (Some Containers will allow you to configure certain types always to be new instances, so that calling get() will always return a new instance, but I am not a fan of that idiom.)

IV

However, if you you consider typehints as communication, then typehinting on Container communicates "the Dispatcher will need to create or locate anything the Container can provide." It's using the Container as a Service Locator, and in general we ought to prefer Dependency Injection.

As an alternative, we might typehint on a ControllerFactory instead. That kind of typehint communicates a narrower requirement: "the Dispatcher will need to create new Controller instances."

Putting together a ControllerFactory is easy enough ...

class ControllerFactory
{
    protected $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function new(string $suffix) : Controller
    {
        $class = 'App\Http\Controller\\' . $suffix;
        return $this->container->new($class);
    }
}

... and then the Dispatcher can depend on that, instead of the Container:

class Dispatcher
{
    protected $controllerFactory;

    public function __construct(ControllerFactory $controllerFactory)
    {
        $this->controllerFactory = $controllerFactory;
    }

    public function dispatch(Route $route)
    {
        $object = $this->controllerFactory->new($route->getController());
        $method = $route->getAction();
        $params = $route->getParams();
        return $object->$method(...$params);
    }
}

Of course, the ControllerFactory itself now depends the Container -- the dependency on the Container just moved, it didn't disappear. Even so, this arrangement is less objectionable for a couple of reasons:

  • The "creation of objects" concern remains separated, per Hevery's guideline "to have either classes with logic OR classes with new operators."

  • The Controller instances being created really are likely to need a wide range of many different object injections, including shared objects from the Container. The typehint of Container is an accurate communication here.

V

As often happens, the answer leads to more questions. In this case, I begin to wonder about the kinds of objects that belong in a Container, per Misko's definitions. For example, is an HTTP Request object something that ought to be created and retained within a Container? I can think of no Request implementations that depend on Injectables; it seems more like a Newable, per Misko, in that it exists as a leaf on the object graph.

Well, I will leave that for another day. Many thanks to ahundiak for correcting me, or least leading me to correction, on this topic.


See the Reddit conversation on this post here.

Controllers are not Services

Controllers (in webbish MVC) and Actions (in ADR) are not Services. That is, their instances are not shared throughout the system. They are not shared objects used in many different places. Each is created and used only once, in one place, usually as the result of routing logic.

As such, Controllers and Actions should not be defined as "Services" in Dependency Injection containers. They should not be in a Service Locator, either.

Instead, try to use a Factory to create the one Controller or Action that you need for the interaction.

UPDATE (7 Dec 2019): Based on the Reddit discussion below, I have reason to revise my opinion. Look for a followup post in the next couple of days.


See the Reddit conversation on this post here.

Teams do not accomplish anything of genuine intellectual value

[T]eams are for normies, for neurotypicals, for trash people who can’t retain multiple levels of variable dereferencing in their heads while coding.

Teams do not accomplish, and have never accomplished, anything of genuine intellectual value. The history of scientific progress is a history of individuals.

Yes, you need a "team" to actually assemble the atomic bomb or the Intel Itanium or a commercial software product. You don’t need a team to conceive it and do the mental heavy lifting.

The effective IQ of a team is the same as the lowest IQ in the team; the productivity of the team is a minor percentage of the productivity you could get from its smartest member working alone.

Every once in a while you will see one brilliant person be inspired by another brilliant person in the near vicinity. This happens once for every hundred million times a "team" crushes the abilities of its members.

Science, even computer science, is not football.

I find myself sympathetic to this outlook. Via Weekly Roundup: The Passion Of Saint iGNUcius Edition.