Paul M. Jones

Don't listen to the crowd, they say "jump."

Service Classes, Payloads, and Responders

Revath Kumar has a good blog post up about extracting domain logic from controllers and putting that logic in a service class. After reading it, I commented that with a little extra work, it would be easy to modify the example to something closer to the Action-Domain-Responder pattern. In doing so, we would get a better separation of concerns (especially in presentation).

Using the code that Revath gives in his blog post as a basis, we can do the following:

  1. In the service class, instead of sometimes throwing exceptions and sometimes returning arrays, we always return Payload instances. These explicitly state the result of the domain activity (“input not valid”, “order created”, “order not created”, “error”). Making the status information explicit in the Payload means that we don’t need to catch exceptions in the controller action, and that we don’t need to examine the domain objects themselves to interpret what occurred in the domain. The service class can now say explicitly what occurred in a standardized way.

  2. In the controller action, now that we don’t need to catch exceptions, we can concentrate on a much smaller set of logic: get the user input, pass it to the domain, get back the domain payload, and pass the payload to a responder.

  3. Finally, we introduce a Responder, whose job is to build (and in this case send) the response. The responder logic ends up being simplified as well.

The modified code looks like this:

use Aura\Payload\Payload;

class OrdersController extends Controller {
  public function actionCreate() {
    $orderData = Yii::app()->request->getParam('order');
    $order = new OrdersService();
    $payload = $order->create($orderData);
    $responder = new OrdersResponder();
    $responder->sendCreateResponse($payload);
  }
}

class OrdersResponder extends Responder {
  public function sendCreateResponse($payload) {
    $result = array('messages' => $payload->getMessages());
    if ($payload->getStatus() === Payload::CREATED) {
      $this->_sendResponse(200, $result);
    } else {
      $result['status'] = 'error';
      $this->_sendResponse(403, $result);
    }
  }
}

class OrdersService {

  protected function newPayload($status) {
    return new Payload($status);
  }

  public function create($orderData) {
    if(empty($orderData['items'])) {
      return $this->newPayload(Payload::NOT_VALID)
        ->setMessages([
          "Order items can't be empty."
        ]);
    }
    $items = $orderData['items'];
    unset($orderData['items']);
    try {
      $order = new Orders;
      $orderTransaction = $order->dbConnection->beginTransaction();

      $address = Addresses::createIfDidntExist($orderData);
      unset($orderData['address']);
      $orderData['address_id'] = $address->id;
      $amount = 0;
      foreach ($items as $key => $item) {
        $amount += $item['total'];
      }
      $amount += $orderData['extra_charge'];
      $orderData['amount'] = $amount;
      $order->attributes = $orderData;
      if($order->save()) {
        if(OrderItems::batchSave($items, $order->id)) {
          $orderTransaction->commit();
          $this->sendMail($order->id);
          return $this->newPayload(Payload::CREATED)
            ->setMessages([
              "Order placed successfully."
            ]);
        }
        $orderTransaction->rollback();
        return $this->newPayload(Payload::NOT_CREATED)
          ->setMessages([
            "Failed to save the items."
          ]);
      }
      else {
        // handle validation errors
        $orderTransaction->rollback();
        return $this->newPayload(Payload::ERROR)
          ->setMessages($order->getErrors());
      }
    }
    catch(Exception $e) {
      $orderTransaction->rollback();
      return $this->newPayload(Payload::ERROR)
        ->setMessages([
          "Something wrong happened"
        ]);
    }
  }
}

Now, there are still obvious candidates for improvement here. For example, we could begin separating the controller action methods into their own individual action classes. But baby steps are the right way to go when refactoring.

This small set of changes gives us a better separation of concerns, especially in terms of presentation. Remember, the “presentation” in a request/response environment is the entire HTTP response, not just the response body. The above changes make it so that HTTP headers and status code presentation work are no longer mixed in with the controller; they are now handled by a separate Responder object.



Cholesterol Is Not Bad For You; or, The 8 Stages Of Science Scams

1) it is propagated by scientists on a non-scientific mission

2) it is believed because it plausibly explains an observation (increasing global temperature [for a time], increasing heart attacks from smoking in the 1950s and 60s). It taps into large anxieties about too much wealth, too much happiness, in western societies. There must be sin somewhere, and the public is ready to flog itself in the cause of a secularized idea of God, uh, I mean Good.

3) the causal relationship is weaker than first supposed; the research is found to be sloppy, the facts have been fudged, subsequent studies do not fully support the original claims, nevertheless the orthodoxy is promulgated all the more harshly for being doubted.

4) by now, powerful economic and ideological interests have taken hold. They supply an ongoing source of funds and opinion to ensure the perpetuation of the alarm: in the case of cholesterol, the margarine industry, the pharmaceutical industry, and the medical establishment, and in the case of AGW, the tribe of bureaucrats and leftists who seek to control markets, whose god of Marxism had failed, and who needed a new god (Gaia) to justify their rule.

5) The skeptics who have patiently argued on the basis of facts that the science of each phenomenon was weak, are ostracized by the opinion establishments of medicine and global warming. Cranks, but the cranks are right and the orthodox priests and Levites are wrong.

6) Eventually, after fifty or sixty years, the subject of discussion just changes. In the case of cholesterol, the evidence gets weaker and weaker, and the problems caused by too much sugar consumption (obesity, diabetes), caused in part by people not eating enough fats and meats, reaches a stage where it can no longer be ignored.

7) the retreat of the orthodoxy is covered by a smokescreen of fresh concerns for some other catastrophe. No admissions of error or apologies for wrecked careers and following bad science are ever issued. Time flows on, bringing neither knowledge nor greater understanding of the role of folly in human affairs.

8) stages 6 and 7 have been reached in the cholesterol cycle; they are beginning in the anthropogenic global warming scam. Fifty years from now, there will still be clanking windmills in the North Sea, but whether they will be still linked to a power grid is less likely, and whether anyone will pay attention is doubtful. The lobbies that keep them there, however, will still exist.

Source: RIP: The great cholesterol scam (1955 - 2015) - Barrel Strength


National Debt: "We Owe It To Ourselves"? Not Quite.

The burden of the debt is that we create an ever-deeper conflict of interest between Lenders and Spenders. Yes, if you think of Lenders and Spenders collectively, you can say that “we owe the debt to ourselves.” But that is a dangerously vacuous way of looking at it.

An excellent analysis of national debt. In short, one person is doing the lending, and another person is doing the spending. At some point you need to pay pack the specific person who did the lending.

Source: Lenders and Spenders: Confronting the Political Reality of Debt - AEI


A Factory Should Create, Not Retain

In a recent Reddit conversation, some of us went off on a tangent about factories. I maintained then, and do now, that a “factory” always-and-only returns a new instance. If you have a “factory” that returns anything other than a new instance, it’s not a factory alone. In the case of factory methods, it is a factory + accessor; in the case of factory objects, it is a factory + registry.

A “factory” (whether a factory method or factory object) is one way to separate object creation from object use.

Let’s say we need to create an object to do some work in a class method:

class Example
{
    public function __construct($db)
    {
        $this->db = $db;
    }

    public function doSomething($itemId)
    {
        $data = $this->db->fetchOne(
            "SELECT * FROM items WHERE id = :id",
            ['id' => $itemId]
        );
        $item = new Item($data);

        // do some other work with the item,
        // the return the results of that work.
        return $results;
    }
}

The item creation is mixed in with the use of the item. What we want to do is separate the creation from the usage. One way to do that is to use a factory method, or a factory object, to handle object creation for us. Here’s an example of a factory method:

class Example
{
    public function __construct($db)
    {
        $this->db = $db;
    }

    public function doSomething($itemId)
    {
        $data = $this->db->fetchOne(
            "SELECT * FROM items WHERE id = ?",
            ['id' => $id]
        );
        $item = $this->item($itemId);

        // do some other work with the item,
        // the return the results of that work.
        return $results;
    }

    public function item($data) // factory method
    {
        return new Item($data);
    }
}

Here’s an example of an injected factory object:

class Example
{
    public function __construct($db, $factory)
    {
        $this->db = $db;
        $this->factory = $factory;
    }

    public function doSomethingWithItem($id)
    {
        $data = $this->db->fetchOne(
            "SELECT * FROM items WHERE id = ?",
            ['id' => $id]
        );
        $item = $this->factory->item($data);

        // do some other work with the item,
        // the return the results of that work.
        return $results;
    }
}

class Factory // factory object
{
    public function item($data) // factory method
    {
        return new Item($data);
    }
}

There were some folks in the Reddit thread that believe a factory may additionally retain the created instance for reuse. For example, let’s say we create and the reuse a collaborator object of some sort:

class Example
{
    public function doSomething()
    {
        $collab = $this->collab();
        // do stuff, then:
        return $result;
    }

    protected function collab() // factory method?
    {
        if (! $this->collab) {
            $this->collab = new Collab();
        }
        return $this->collab;
    }
}

As far as I can tell, that’s not just a factory. There are three things going on there: initializing a property, creating an object, and accessing a property. To split the concerns, one would need two methods:

class Example
{
    public function doSomething()
    {
        $collab = $this->getCollab();
        // do stuff, then:
        return $result;
    }

    protected function getCollab() // initialize + access
    {
        if (! $this->collab) {
            $this->collab = $this->newCollab();
        }
        return $this->collab;
    }

    protected function newCollab() // factory
    {
        return new Collab();
    }
}

Now the concern of creating the object is represented by newCollab() method, and the concerns of initializing and accessing the property are represented by the getCollab() method. Indeed, splitting out a factory method in this kind of situation is the exact recommendation in the GOF Design Patterns book on page 113; this is the book that defined the term "factory method" in the first place, so it seems authoritative on this point.

What happens when you add retention to what would otherwise be a factory object? For example, is the following only a factory object, or does it do more than just create and return new instances?

class WhatIsThatThing
{
    public function getService()
    {
        if (! $this->service) {
            $this->service = $this->newService();
        }
        return $this->service;
    }

    public function newService()
    {
        return new Service();
    }
}

It both creates objects, and retains the created objects. That makes it more than just a factory; it looks more like a container at this point.

Finally, regarding method names, it seems like it’s best to indicate what to expect as a return result. I default to newInstance() in factory objects that deal with only a single class, and new<Type>() when the factory object creates many different classes. Using get<Type>() indicates that a pre-existing instance (probably memoized in a property) is being returned.



"Of course you have freedom of speech! You just don't get to lie."

Democracy depends on having a strong sense of the value of diverse opinions. If one imagines (as the Soviets did) that one already has the final truth, and that everyone who disagrees is mad, immoral, or stupid, then why allow opposing opinions to be expressed or permit another party to exist at all? The Soviets insisted they had complete freedom of speech, they just did not allow people to lie. It is a short step, John Stuart Mill argues, from the view that one’s opponents are necessarily guided by evil intentions to the rule of what we have come to call a one-party state or what Putin today calls “managed democracy.” If universities embody the future, then we are about to take that step.

Source: Article Why College Kids Are Avoiding The Study Of Literature


Modernizing Serialized PHP Objects with class_alias()

Several weeks ago, a correspondent presented a legacy situation that I've never had to deal with. He was working his way through Modernizing Legacy Applications in PHP, and realized the codebase was storing serialized PHP objects in a database. He couldn't refactor the class names without seriously breaking the application.

I was carefully moving my classes to a PSR-0/4 structure when I found this. The application saves the output of serialize($shoppingCart) in a BLOB column, and unserializes it later to recreate the ShoppingCart object. The serialized object string looks like this:

O:12:"ShoppingCart":17:{s:13:"\00Basket\00items";a:25:{...}; ...}

See how the class name is embedded in the serialized string? If I rename the ShopppingCart class to PSR-0/4 namespace, then the old class won't be found when the application tries to unserialize() the serialized representation. How can I begin refactoring this without breaking the whole application?

Before I was able to reply, my correspondent ended up changing the serialization strategy to use JSON, which was a rather large change. It ended up well, but it turns out there is a less intrusive solution: class_alias().

If you're in a serialized situation, and you need to change a class name, you can use a class_alias() to point the old class name to the new one. (Call class_alias() early in execution, probably before you register your autoloader.) You can then rename and move the class according to PSR-0/4 rules, and PHP will handle the rest for you.

For example, if you renamed ShoppingCart to Domain\Orders\Cart, you might do this:

class_alias('Domain\Orders\Cart', 'ShoppingCart');

Now when you call unserialize($shoppingCart) to create an object, PHP will create it as an instance of Domain\Orders\Cart instead of ShoppingCart. Re-serialized representations of the recreated object will retain the new class name, not the old one: O:18:"Domain\Orders\Cart":....

As soon as there are no more serialized representations using the old class name, you can remove the class_alias() call entirely.



The Failure of Female Engagement Teams in Afghanistan

Female Engagement Teams in Afghanistan were easily manipulated by the locals and proved to be largely ineffective in their intended counter-insurgency role.

...

Azarbaijani-Moghaddam found that the FETs were easily manipulated by Afghans with experience of three decades of relief and development interventions prior to the arrival of all these well-intentioned young military personnel in their area. There was, in fact, very little understanding within the military regarding the role of women, potential and actual, both within the insurgency in Afghanistan and in support of it. - See more at: http://spp.ceu.edu/article/2014-03-19/failure-female-engagement-afghnistan#sthash.1jqxoP9d.dpuf

Source: The Failure of Female Engagement Teams in Afghanistan | School of Public Policy


MLAPHP Boot Camp!

You may have seen my introductory talk on steps toward modernizing a legacy application at Nashville PHP or at php[world]. That was the presentation that formed the first few chapters of Modernizing Legacy Applications in PHP.

The MLAPHP book has been a great help to a lot of people. But there are a lot of other developers who learn best by watching-and-listening first, instead of reading. They know it can be a great help to have someone talk them through the whole moderizing process, and see the steps being performed.

Usually you have to go to a conference for that sort of thing. You have to pay for the ticket, and for the hotel, and for travel, and meals, and everything else. Even if your employer helps with the money, there's still the time involved: you have to be away for several days at a time.

Well, now you can have a conference-level training experience in the comfort of your own home, without the travel hassle and hotel expense. I have put together an online weekend "boot camp" where we go through the entire modernization process, from basic prerequisities at the beginning to setting up a DI container at the end. After that end-to-end study of the steps involved, you should be able to jump-start your own modernizing project much more easily.

The 8-hour camp will combine lecture and "live" coding with examples. In particular, there will be plenty of opportunity for you to get answers specific to your own modernizing situation, and to chat with other attendees.

The two-day camp will be on Sat 11 July and Sun 12 July. Each day will run from 12 noon to 4pm (US Central Daylight), with time for breaks built in. That makes it 10am-2pm for Pacific time zone attendees, and 1-5pm for Eastern, which should be convenient for almost everyone.

With your ticket to attend the boot camp, you get:

  • Two days of online boot camp, four hours each
  • A review of the entire modernization process from beginning to end
  • A bonus recording of the camp
  • For $399

This might be the only time I lead this kind of boot camp, so get your ticket while there are still seats available!



Technical Speaker Uninvited When SJWs Politicize Event

Latest hullaballoo: Curtis Yarvin (aka “Mencius Moldbug”) was invited to give a presentation on his new computer system Urbit to the Strange Loop tech conference. Then some of his ideological enemies (actually literal Communists) found out, objected to his political views, and he got banned from the conference.

Article here, Hacker News thread here, impressively prescient Moldbug post here, demonstration of inevitable Streisand Effect here.

I did consider not linking this since it’s so obviously toxoplasma, but I was convinced to do so by this letter where the conference organizer states he’s never read any Moldbug himself, but decided to cave to the ban request because otherwise politics overshadow the conference, which was supposed to be about tech.

This kind of crystallizes a pattern I’ve been noticing recently where some social justice activists use a tactic along the lines of “Nice institution youse gots here, shame if somebody were to politicize it”.

I sympathize with the desire to give into that to avoid trouble, but I think maybe the only way to avoid enshrining that kind of heckler’s veto always working is to make it clear that the choice to give in will also be politicized.

Maybe if organizers know that banning all insufficiently-leftist-people and not banning all insufficiently-leftist-people will both result in politicization and Internet firestorms, they’ll say “screw it” and just follow their principles.

Via Slate Star Codex. Apparently you're not allowed to speak about anything at all if you don't have The Right Political Opinions At The Right Time, especially when the #hashTagMob start bullying and heckling. The best response to the #hashTagMob is to double down and invite *more* people they disagree with. Giving in gives them the ability to say "See, we were right!" and then they'll do more of it. Once you pay extortion, you never get rid of the extortionist.


Relay: A PSR-7 Middleware Dispatcher

UPDATE (2015-06-09): Due to a conflict with the "pipeline" design pattern name, which this project does not implement, the project name has been changed from Pipeline to Relay. Links and naming have been updated inline, with the original text block quoted beneath.

In a fit of inspiration over the weekend, I extracted the middleware dispatcher from the Radar ADR core into its own standalone library: Relay. If you need to execute a queue of middleware, Relay is for you.

Relay uses a common PSR-7 middleware signature: function ($request, $response, $next) and return $response. That is what Slim 3 uses, along with Stratigility and Radar, and is modeled on Sencha Connect. Any callable/invokable with that signature will work with Relay.

As a standalone library, Relay is framework-independent, so you can use it anywhere. You could even build your own framework around it, picking a dotenv-loader of your choice, a DI container of your choice, and a middleware queue of your choice.

Speaking of DI containers, Relay is also container-independent. You can use any dependency-injection system you like to build your middleware queue and pass it to Relay. All you need to do is pass in a callable that converts each queue entry to an object or callable. Try it with PHP-DI, Pimple, Auryn, or even Aura.Di.

I have converted Radar to use Relay at its core, and soon I'll be extracting two of the basic Radar middleware classes to standalone packages. When I do, they'll be listed on the Relay wiki.

ORIGINAL RELEASE:

In a fit of inspiration over the weekend, I extracted the middleware dispatcher from the Radar ADR core into its own standalone library: Pipeline. If you need to execute a queue of middleware, Pipeline is for you.

Pipeline uses a common PSR-7 middleware signature: function ($request, $response, $next) and return $response. That is what Slim 3 uses, along with Stratigility and Radar, and is modeled on Sencha Connect. Any callable/invokable with that signature will work with Pipeline.

As a standalone library, Pipeline is framework-independent, so you can use it anywhere. You could even build your own framework around it, picking a dotenv-loader of your choice, a DI container of your choice, and a middleware queue of your choice.

Speaking of DI containers, Pipeline is also container-independent. You can use any dependency-injection system you like to build your middleware queue and pass it to Pipeline. All you need to do is pass in a callable that converts each queue entry to an object or callable. Try it with PHP-DI, Pimple, Auryn, or even Aura.Di.

I have converted Radar to use Pipeline at its core, and soon I'll be extracting two of the basic Radar middleware classes to standalone packages. When I do, they'll be listed on the Pipeline wiki.