Backend Developers are Great at UX

That's kind of a provocative title, so let me just get this out of the way: No, no they are not. And I am not crazy enough to attempt to convince you otherwise. That said, they aren't nearly as bad as they're given credit for.

Let's do this by way of example. Suppose you have a list, and users need to be able to sort it, alter the items in the list, and delete items. All your front-end developers are busy, and so are the UX people, so it's up to that backend developer to bang something out. What are they going to give you? Something, I suspect, an awful lot like this:

Sort Item Delete?

In other words, a <table> that closely mimics the underlying database structure. Yeah, I can hear the internal screams of the UX people from here. But let's consider this for a moment. Is this going to be fun to use? No. Definitely not. But in its straightforward simplicity, it gives us something that's kind of amazing: anybody can use this form. No matter how spotty your network connectivity, if you managed to load this form, you can submit it. If all you have is a text-only browser, you can use this form. No mouse? That's okay, this form is keyboard-accessible. Do you interact with your computer via voice command? This form will be serviceable.

For the vast majority of your users, this is not great UX. But it is Universal UX. Anybody―everybody―can use it! The web is universally accessible by default, and by staying away from the fancy stuff, by building something that would be at home in 1994, our backend developer managed to preserve that.

We definitely don't want to stop here, but it's a pretty great jumping-off point. So let's put our UX hat on and start making some improvements.

Sort Item Delete?

Some quick wins are simply to adjust the sort values to make rearranging easier, and adjusting the text of the button. Not terribly complicated, even the backend developer can manage it.

Sort Item Delete?

But of course, manually entering the sort weight is awful, so maybe we add some buttons to adjust the list sorting, so users can click a button, rather than type in sort values, and hide the numeric input with a little CSS. We'll leave it in the DOM both for text-only browsers, and to give a place for our buttons to store the sort order (assuming they function via JavaScript).

Sort Item Delete?

And as we get fancier, maybe we dim or strike-through the to-be-deleted rows, to make it obvious they're going to go away. We add a little JavaScript to enable drag-and-drop of the rows, for really simple sorting. Maybe we even add some keypress handlers so people can move things in the list by pressing C-x C-t or whatever seems appropriate. And if those scripts load successfully and work in the user's browser, maybe we even hide the explicit sort buttons from visual users, to avoid clutter. You do run the risk of excluding a small contingent of users that way―if you can only interact with a computer through eye-movements, visible buttons might be kind of handy―but for all I know they may have other ways of handling that, so if you've got the budget, maybe test that sort of thing and report back to the rest of us. I'd certainly love to know.

But in the end, what we end up with is a lot closer to what you might have designed as a visually-oriented UX person, but because we built it in stages, because we started with the basics and layered things on top, it's usable in far more scenarios than it might otherwise be had we started with a Photoshop mockup of the end result.

NB: As you may have noticed, there is no JS attached, and there isn't much in the way of styling. That's partly due to platform limitations, but mostly because this isn't really meant to be about how-to-build it, but more about what-to-consider in the design. It just so happens that if you build it in a certain order, those considerations naturally reveal themselves.

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

Alls Quiet Without Power

Last night, while attempting unsuccessfully to acquire sleepytimes, I heard a loud bang. This was quickly followed by the fomf of the power going out, and a short while later by the beeping of battery backups now without power.

Naturally, the first thing I did was go to shut down my computers. My first hint that this was more than a nearby transformer blowing is that my internet was out. My end is, naturally, well powered, but apparently my ISP does not provide battery power at their end, and their end was also without power.

Computers safely shut down, I wandered outside to see how widespread the problem was. The neighbors were without power. The streetlights, without power. I look up and down the street, and the neighboring blocks are, you guessed it, without power.

This can only mean one thing: something at the nearby substation blew.

So, naturally, I wander in the direction of the substation. On my way, I run into a police patrol. They don't stop me, but they pause briefly as they drive by to think about it. It's been maybe ten minutes, and they're already patrolling the neighborhood—a pretty impressive response time, though it seems weird that they'd respond to that at all.

A little bit later, I see some firetrucks. Nothing was on fire, so I have no idea what they were responding to, but okay. I guess they're out for the power outage as well? Well, that or they're breaking into the auto-parts store. I can't really tell.

The power company isn't at the substation yet, but that's not surprising: in all likelihood, some poor lineman has to wake up first.

So I wander around the neighborhood, to explore it in its unlit, silent glory. And it was awesome! No streetlights burning bright (the city has been slowly replacing the yellow lamps with bright blue LEDs, and if the yellow ones weren't bad enough the blue LEDs are awful). The usual ever-present hum of air conditioners was gone. And in spite of the streetlights being out, there was plenty of light to see by—though the moon being only a day or two off from full certainly helped with that.

Still no power company at the substation. But I do notice something: the nearby stoplight is blinking red. It was affected by the power loss, and has degraded itself to a four-way stop. Fascinating!

I turn around to head home, and am struck with an idea. So I wander several blocks over to the retail shops, and explore an unlit street, full of shops lit only by their emergency lights. Once in a while, I'll pass a building emitting the slow beep beep beep of a battery backup. Interestingly, the collision repair shop has plenty of lights on, and emits the unmistakable hum of a generator. I can only assume it kicked on automatically, since few people would be around so early to start it.

I head home, with a quick detour to the substation, where a pickup is just arriving. A few hours later, we finally got power again.

Losing power confirmed something I've long thought: getting rid of streetlights would be awesome! Particularly on the residential streets, where they're just not needed. Particularly that freshly installed bright blue LED two houses down that casts the glow of cheap office lighting across the entire gorram block.

It also confirms that several hours without A/C is several hours too many. Ugh.

And that my ISP needs to get on the ball, and make sure internet continues to function during a power outage. You're a phone company, making sure things continue to work should be second nature!

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

What Makes a Good Front-End Developer?

While I am ostensibly a "full-stack" web developer, it's no secret that I'm not particulary fond of the front-end. In large part, this may be because the world seems to be full of bad front-end developers, who by and large are fantastic at building crappy versions of desktop apps inside a browser, but are incredibly bad at building things which are truly of the web.

What makes a good front-end developer? I asked @janiukjf this after her presentation at the ExperiencingUX meetup last night, and she says part of it is a willingness to stay up to date with the constantly-popping-up front end frameworks. And certainly, the front-end changes quickly and it's hard to keep up.

But do we need to keep up? I'm not convinced we do.

After all: a regular form post has worked since the 90s. It's not going to stop working! We built websites without CSS for years―CSS is a wonderful addition, but if your website is nonsensical without CSS, it'll be nonsensical in a text-only browser. It will potentially be less useful to a screen-reader (an h1 and a div with an enlarged font are likely to be expressed differently) or other assistive technology. But even with CSS, you don't have to be on the cutting edge to do useful, beautiful things. In fact it probably helps to avoid being on the forefront: older CSS tends to work better and in more browsers.

And then there's JavaScript: the easiest way to turn a browser into a fragile, distributed computing environment. We built websites without JS for over a decade, and eschewing megabytes of JavaScript to display basic text would greatly improve the speed of the web. Properly applied, JavaScript can be used to do amazing things, but there's no shame in making a simple line-of-business CRUD app out of plain ol' 90s-era forms if that's all it really needs.

So what makes a good front-end developer? I think it's embracing the limitations of the web. It's understanding that the web isn't a pixel-perfect medium; that sometimes your images or fonts or styles or scripts won't load and you have to handle that; it's understanding that the web is populated not just by developers with the latest Macbook and ten-year-olds with iPhones, but also little old ladies with dusty old Gateway computers and cheap faded monitors, and the web should work for all of them. It's understanding that the browser is a hostile computing environment in which anything we tell it to do is a mere suggestion and if we break when it doesn't that is our fault and we need to handle it.

And quite frankly, that's really hard.

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

  • Current Mood
    thoughtful thoughtful
  • Tags

healthcare.gov's Depressingly Awful UI

A while back I made an attempt to use healthcare.gov to acquire health insurance. The experience was … unpleasant. Here are some things that irked me:

JavaScript

It's broken without JS. While this is incredibly common, it will always garner a complaint from me. If I am in a browser I do not want an "app-like" experience, I want a web-like experience.

It includes JS from third parties. Look, maybe you trust Google, MxPnl, or Optimizely, but I sure don't. On the bright side, it worked even without running JS from those companies—though I don't know whether the credit goes to NoScript's surrogates or the HC.gov developers.

Laggy

It felt very sluggish while I was attempting to use it. When I entered my zip code, it would miss keystrokes. E.g., if I keyed in "90210", what appeared in the field would be more like "91". Clearly it's doing a network request to give me a list of cities, but is it doing it synchronously or something? Because wow is that a terrible experience.

Poor Name Handling

It told me my first name was invalid. I'm used to systems mucking up other parts of my name, but that was a new one. Unfortunately, I don't remember what I originally tried to enter. (Probably my initials, since that's what I go by.)

The name suffix is a select. It contains Sr., Jr., III, IV, and sometimes V. So much for Henry VIII. Or me, for that matter, because I'm a II (NB: Jr. and II are not equivalent). I think in the end I made the suffix part of my last name.

Notice that sometimes V? That's because I came across two name selects. The second was missing the V, which means the two selects aren't even pulling from the same source. (For that matter, why am I entering this data multiple times? Last I checked computers were really good at copying. Just ask the MPAA.)

Lousy Identity Verification

Identity verification systems are pretty much always terrible because they pretend public information is a shared secret, and this is no exception. My name and address are both public, and my SSN might as well be given the number of organizations that have it on file. The credit bureaus they use to verify my identity, for example, are companies I have never directly interacted with or provided any information to, and yet they have all this information. When third parties have your data through no fault of your own, that's pretty much the definition of non-private data.

The follow-up identity verification questions are at least as terrible. One of them was "County for the provided address". What is that even verifying? That I know what address I just gave you?

Multiple Paper Forms, Now Online

I think I accepted the privacy policy something like half a dozen times. And had to enter my personal information—address, e-mail, etc.—multiple times as well. Did they just do a direct translation of the various paper forms to the web or something? Because that's awful.

Even some of Q&A walkthrough steps felt like paper forms directly copied to the web. "Did you recently lose coverage?" "Yes." "Are you losing coverage in the next 60 days?" … I'm pretty sure the answer to the first question makes the second one not applicable!

Unnecessary Info Required

As far as I can tell, insurance rates must be the same regardless of sex, so why does it require me to specify that? Also, the error for failure to fill out the sex field is hilarious: "select at least one item". Naturally, it enforces a gender binary and doesn't allow you to pick both.

It requires a phone number. So what do people without phones do? Or people who just plain don't like phones. Alas, I did not attempt to enter an invalid number like 555-0123, so maybe it takes those? I used a voicemail-only number I maintain specifically for such forms.

Unclear Results

So when I finally got all the way through, what are the results of my application? It says "Eligible to purchase health coverage through the Marketplace", and I think "Yay, I can finally move on to the thing I was actually trying to accomplish!". So I keep reading in the "What should I do next?" section and it tells me "You cannot choose or change plans at this time…".

Have I been mistaken about the meaning of eligible all these years? Because I thought it meant you can do something, and it's telling me the opposite. I get what it's telling me now—I could, if only some other conditions were met—but wow is that ever confusing.

Suspicious Goodbye

Defeated, stressed, and missing hours of my life I'll never get back, I log out. That takes me to cuidadodesalud.gov, whereupon I am presented with a blank page. (JS is not enabled for that domain because I've never been there, obvs.) I guess that's the Spanish version of healthcare.gov? Not sure why it decided to send me there, but after a long frustrating experience, being dumped onto a suspicious letter salad domain is a fitting cherry on top.

Final Thoughts

I guess on the upside all my complaints are about details, which means at some level it's at least functional. But I think I'd rather pay the fine for not having health insurance than put myself through that a second time, which pretty much defeats the entire point of the site.

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

CL-FTP Bugs Squashed

One of the perks of being unemployed are that I have a reasonable amount of downtime again, so I've been spending some of it updating libraries which are under my care.

CL-FTP, which is pretty stable and incredibly niche (who uses FTP anymore, anyway?), has recently had a flurry of activity. Thanks to Kambiz Darabi for finding and fixing a bug related to :if-exists nil. Thanks also to Rafael Jesús Alcántara Pérez for improving ABCL compatibility.

CL-FTP is now at version 1.6, and includes both the above-mentioned bug fixes as well as:

  • Now available via the ASDF system name "CL-FTP", in addition to "FTP". The inconsistency between library name and system name bothered me, so now they're consistent.
  • No more docs hidden away in an LML file. The method docs have been moved into docstrings, which hopefully puts things a little closer to where they should be. (And hey, maybe they'll be picked up by quickdocs in the future.)
  • "active" FTP should actually work now. Turns out it's been broken for, uh, entirely too many years. It may or may not work depending on NATs and firewalls in between the client and the server, but the library itself should no longer be an issue.

In related news, a big thanks to Mariano Montone for his patches to burgled-batteries. You may be interested to check out his burgled-batteries.syntax project, which helps bridge the gap between what burgled-batteries actually is and the ambitious goals I have yet to get anywhere near.

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

Clojure Is For Me, Go Is For My Team

Before my now-previous employer folded, we were being courted by a buyer (boy, was that time period an emotional roller-coaster!). This would have changed our development direction somewhat, and so at the behest of my boss I spent a couple of weeks exploring language options for our upcoming greenfield projects.

I was asked to explore Clojure and Go, and compare them to our existing language, PHP. I decided to evaluate the languages by porting a fairly stand-alone portion of our existing app into both Go and Clojure, and comparing it to the PHP version.

The Basic Problem

That relatively stand-alone portion of our app was our recipe importer. It would allow users to import recipes from external sites, for use within our system.

There are a number of standards for recipe formats: the hRecipe microformat, schema.org's Recipe format, RDF, data-vocabulary.org's Recipe format, and probably a few others. In addition, most of the sites we explicitly supported either fail to mark up the entire recipe, interpreted the spec they purported to follow in strange ways, or merely referenced a recipe from another site, requiring us to follow the link chain to a parsable source.

In other words: it's a real (non-toy) problem, it's sufficiently complicated to get a reasonable feel for a language, and it's simple enough it can be ported within a relatively short timeframe.

The Method

I spent a week in each of Clojure and Go. This was not enough time for a full feature-parity port with the PHP version, but sufficiently long to present most of the complexity of the problem (inheritance, parser registration, and so forth).

Inheritance Is… Uh… Missing?

Neither Go nor Clojure support "classical" OO inheritance. It may be my brain is broken through years of shoehorning things into inheritance hierarchies, but it seems to me this particular problem happens to be a pretty good fit for classic OO. "Site X uses format Y, with these overrides."

So the biggest stumbling block in both languages was simply coming up with a way to model the problem. To be perfectly honest, the solution I ended up in both languages looks pretty much like classic OO shoehorned into whatever the language does support (embedded structs in Go, multimethods in Clojure), and would almost certainly not be considered idiomatic by people with more experience in each language. (But then, neither would my PHP, and I've been doing that for a very long time.)

Clojure

As a lisper bent on proving that a lisp was a viable option, I started with Clojure.

I spent approximately three days figuring out how to even model the problem without classic OO inheritance, and the following two building three generic parsers and two site-specific ones.

It was one of the most enjoyable weeks of my tenure. Clojure is as flexible as you'd expect a Lisp to be, the code was compact, reasonably fast, and I was reminded of how much I'd been missing interactive development.

When I presented it alongside the PHP it was a port of, reactions were mixed. Some developers remarked that they had a very difficult time understanding it, and that it would likely prevent the developers who worked on other codebases (e.g., our mobile developers) from swooping in to make a quick fix. My boss, who had apparently spent a significant amount of time attempting to do something useful in Clojure without much success, remarked that the comparison made Clojure much easier to understand for him than it had been previously.

Go

Next I tried Go. Having already faced a lack of inheritance, and presented with Go's much smaller field of options to choose from, I was able to jump right in, and hit parity with the Clojure version in short order.

I did not particularly enjoy programming in Go. While Go is strongly opinionated in surprisingly good ways, the edit, compile, debug cycle is obnoxious and slow (goauto may have helped reduce this pain), the code ends up verbose and repetitive, and there are little to no facilities for abstracting out patterns.

The Go code received less objection when presented. The lines were significantly longer than either the PHP or Clojure versions, and vertically it was very slightly less dense than the PHP version due to all the error checks.

Subjective Comparisons

Code Feel
PHP Clojure Go

Is it any wonder I prefer lisps? So much meatier.

Learning Curve / Programmer Effectiveness
Go was the easiest to pick up, but there isn't really anywhere left to go once you do. Clojure is definitely harder to become proficient with, but you can leverage that into increased programmer efficiency later. PHP has so many pitfalls that anyone starting out is likely to end up negatively productive at first, writing a horribly insecure buggy mess.
Developer Emotions
Clojure inspired a mixture of enthusiasm and curiosity, with strong concerns for the practicality of finding and training developers in a language which is so different from mainstream ones. Go had an enthusiastic champion in my boss, but was largely met with ennuitic "meh"s by other developers (golang is basically boring-by-design). PHP was loved by none and hated by some, with the only argument for it being "we've already got a bunch of code written in PHP".

Recommendation

I liked Clojure. It's fun to write in, it feels very productive, and the power lisps provide to build your own abstractions is unparalleled. But as varied as the quality of code was in our PHP, providing room for even more variability is a hard case to argue. While I would have loved to recommend Clojure, asking a team of devs who think in terms of C++ to make the transition was more than I could have sold.

Go, on the other hand, solves a lot of problems that we had with PHP. Stuff the wrong type? Go would have caught that. Inconsistently-formatted code? gofmt would have fixed that. Bugs because PHP did something unexpected unless you thoroughly read and retained every aspect of the documentation? Go's house is not built from bundles of thorns.

So while Go may not be the language for me, it would have been the right call for our team.

Available For Work

As you may have guessed by the mention of my previous employer folding, I am presently available for work. Feel free to contact me if you have something you think I may be interested in.

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

I'm Giving A Talk Today!

Apologies for the short notice--I've been rushed just trying to get the darn thing ready--but I will be giving a talk at Iowa Code Camp on Saturday, November 1st.

If you can't attend, or want to review my talk before/after I give it, you can find it here. Feel free to offer any feedback. It's much too late to make major changes at this point, but feedback is welcome regardless.

(Technically the talk is about PHP, but tagged Lisp because I blame Common Lisp for inspiring a bunch of it.)

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

Typehint Conversion Caveat Explained

I was highly amused by the reactions to my previous post on the programming and php subreddits. So I spent a little time to isolate the typehint conversion optional argument issue.

It’s not me, it’s PHP. And frankly, I don’t understand the point of the backtrace going to the trouble of making things references if doing things with those references isn’t even supported.

That bug description isn’t entirely accurate as to what’s going on, however, as some test cases show.

<?php

function f(int $a, int $b = null, int $c = null) {
  error_log(json_encode([$a, $b, $c]));
  error_log(json_encode(func_get_args()));
}

function changeArg($code, $str) {
  preg_match('/^Argument (\\d+) /', $str, $m);
  $i = $m[1]-1;
  $bt = debug_backtrace(null, 2);
  ++$bt[1]['args'][$i];
  return true;
}

set_error_handler('changeArg', E_ALL);

f(3, 2, 1);

Outputs:

[4,2,1]
[4,3,2]

Note that the required argument changes, but the optional argument does not. Also note that func_get_args() returns the altered argument, in disagreement with the actual argument.

Where it gets interesting is if we alter that $i to be $i+1. That is, if we change the argument after the one we got an error about.

<?php

function f(int $a, int $b = null, int $c = null) {
  error_log(json_encode([$a, $b, $c]));
  error_log(json_encode(func_get_args()));
}

function changeArg($code, $str) {
  preg_match('/^Argument (\\d+) /', $str, $m);
  $i = $m[1]-1;
  $bt = debug_backtrace(null, 2);
  if (count($bt[1]['args']) > $i+1) {
    ++$bt[1]['args'][$i+1];
  }
  return true;
}

set_error_handler('changeArg', E_ALL);

f(3, 2, 1);

Outputs:

[3,3,2]
[3,3,2]

Then the change sticks, and the optional argument is modified.

By switching to $i-1, you’ll notice that even the required argument fails to be modified. Which means in the default case where one tries to modify the argument an error was triggered about, the argument’s reference is being broken slightly earlier for optional arguments than for required arguments. That, to me, strongly suggests a bug, because the behavior is inconsistent.

But my use-case isn’t supported, and presumably it doesn’t affect any other use-cases, so I’ll either have to live with it or write a code pre-processor which fixes up the issue. Ah well.

I'm left confused about why there exists such a thing as continuable errors if fixing the error and continuing on isn't supported, but ... PHP isn't exactly known for it's strong sense of feature coherency.

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.

The Terrible, Horrible, No-Good, Very-Bad Things I Do To PHP (Or: Greenspunning in PHP)

Controller Methods

What we call a “controller method”, at least, is simply a function which is called on the web side via AJAX and returns some value back (generally either JSON or a snippet of HTML).

When I started at my current employer, controller methods looked like this:

class MyController extends Controller {
  function f() {
    if (!$this->required('foo', 'bar', 'baz')) return;
    if (!is_numeric($this->requestvars['foo'])) return;
    // lots of code
    if (isset($this->requestvars['quux'])) {
      // do something with quux
    }
    // more code
    return $someString;
  }
}

Aside from being hideous, this has a number of glaring problems:

  1. The error handling is terrible.
  2. Validation is hard, and thus incredibly easy to screw up or forget entirely.
  3. Even something that should be easy―merely figuring out how to call the method―requires reading and understanding the entire method.

This just won’t do.

Surely it would be much nicer if controller methods could simply be defined like a regular function. Fortunately, PHP offers some manner of reflexive capabilities, meaning we can ask it what arguments a function takes. We can then match up GET/POST parameters by name, and send the function the proper arguments.

In other words, we can define the function more like:

class MyController extends Controller {
  function f($foo, $bar, $baz, $quux = null) {
    // lots of code
    if (isset($quux)) {
      // do something with quux
    }
    // more code
    return new Response\HTML($someString);
  }
}

And have it actually work. That’s much nicer. Now, we can call the method from PHP as easily as we call it from JavaScript, and we don’t have to read the entire function to figure out what arguments it takes.

(The astute reader will also notice I’ve moved to returning an object, so the response has a type. This is super-handy, because now it’s easy to ensure we send the apropriate content-type, enabling the JS side to do more intelligent things with it.)

Of course, this only tells us which arguments it takes, and whether they’re optional or required. We still need easier data validation. PHP provides type hints, but they only work for classes. Or do they?

Type Hints

In a brazen display of potentially ill-advised hackery (our code is a little more involved, but that should give you the general idea), I added an error handler that enables us to define non-class types to validate things.

So now we can do this:

class MyController extends Controller {
  function f(
    int $foo,
    string $bar,
    string $baz,
    int $quux = null
  ) {
    // lots of code
    if (isset($quux)) {
      // do something with quux
    }
    // more code
    return new Response\HTML($someString);
  }
}

And all the machinery ensures that by the time f() is executing, $foo looks like an integer, as does $quux if it was provided.

Now the caller of the code can readily know what the value of the variables should look like, and the programmer of the function doesn’t really have an excuse for not picking a type because it’s so easy.

Of course, this isn’t sufficient yet either. For instance, if I’d like to be able to pass a date into the controller, it has to be a string. Then the writer of the controller has to convert it to an appropriate class. Surely it’d be much nicer if the author of the controller method could say “I want a DateTime object”, which would be automagically converted from a specially-formatted string sent by the client.

Type Conversion via Typehints

Because PHP provides references via the backtrace mechanism, we can modify the parameters a function was called with.

class MyController extends Controller {
  function f(
    int $foo,
    string $bar,
    DateTime $baz,
    int $quux = null
  ) {
    // lots of code
    if (isset($quux)) {
      // do something with quux
    }
    // more code
    return new Response\HTML($someString);
  }
}

So while $baz might be POSTed as baz=2014-08-16, what f() gets is a PHP DateTime object representing that date. Due to the implementation mechanism, even something as simple as:

$mycontroller->f(1, “bar”, “2014-08-16”);

Will result in $baz being a DateTime object inside f().

Caveat

There is an unfortunate caveat, and I have yet to figure out if it’s a quirk of the way I implemented things, or a quirk in the way PHP is implemented, but optional arguments do not change. That is, SomeClass $var = null will result in $var still being a string. func_get_args() will contain the altered value, however.

Multiple Inheritance and Method Combinations

PHP is a single inheritance language. Traits add some ability to build mixins, which is super-handy, but has some annoying restrictions. Particularly around calling methods―in particular, you can’t define a method in a trait, override it in a class which uses a trait, and then call the trait method from the class method. At least, not easily and generally.

Plus there’s no concept of method combinations. It’d be really handy to be able to say “hey, add this stuff to the return value” (e.g., by appending to an array) and have it just happen, rather than having to know how to combine your stuff with the parent method’s stuff.

While I’m sad to say I don’t have this working generally across any class, I have managed to get it working for a particular base class where it’s most useful to our codebase. Subclasses and traits can define certain methods, and when called, the class heirarchy will be automatically walked and the results of calling each method in the heirarchy will be combined.

trait BobsJams {
  static function BobsJams_getAdditionalJams() {
    return [ new CranberryJam(), new StrawberryJam() ];
  }
}

trait JimsJams {
  static function JimsJams_getAdditionalJams() {
    return [ new BlackberryJam() ];
  }
}

class Jams {
  function getJams() {
    return (new MethodCombinator([], 'array_merge'))
      ->execute(new ReflectionClass(get_called_class()), "getAdditionalJams");
  }
}

class FewJams extends Jams {
  static function getAdditionalJams() {
    return [ new PineappleJam() ];
  }
}

class LotsOJams extends FewJams {
  use BobsJams;
  use JimsJams;

  static function getAdditionalJams() {
    return [ new OrangeJam() ];
  }
}

(new LotsOJams())->getJams();
// => [ OrangeJam, CranberryJam, StrawberryJam, BlackberryJam, PineappleJam ]

(The somewhat annoying prefix on the traits’ method names is to avoid forcing users of a trait to deal with name collisions.)

Naturally, all the magic of the getJams() method is hidden away in the MethodCombinator class, but it just walks the class hierarchy―traits included―using the C3 Linearization algorithm, calls those methods, and then combines them all using the combinator function (in this case, array_merge).

This, as you might imagine, greatly simplifies some code.

Oh, but you’re not impressed by shoehorning some level of multiple inheritance into a singly-inherited language? Fine, how about…

Context-Sensitive Object Behavior

Web code tends to be live, while mobile code is harshly asynchronous (as in: still needs to function when you have no signal, and then do something reasonable with data changes when you do have signal again), so what we care about changes between our Mobile API and our Web code, and yet we’d still like to share the basic structure of any given piece of data so we don’t have to write things twice or keep twice as much in our heads.

Heavily inspired by Pascal Costanza’s Context-Oriented-Programming, we define our data structures something like this:

class MyThing extends Struct {
  public $partA;
  public $userID;
  // ...
  function getAdditionalDefaultContextualComponents() {
    return [ new MyThingWebUI(), new MyThingMobileAPI() ];
  }
}

class MyThingWebUI extends Contextual {
  public $isReadOnly;
  // ...
  function getApplicableLayer() { return "WebUI"; }
}

class MyThingMobileAPI extends Contextual {
  public $partB;
  // ...
  function getApplicableLayer() { return "MobileAPI"; }
}

The two Contextual subclasses define things that are only available within particular contexts (layers). Thus, within the context of WebUI, MyThing appears from the outside to look like:

{
  "partA": "foo",
  "userID": 12,
  "isReadOnly": false,
}

But within the Mobile API, that same $myThing object looks like:

{
  "partA": "foo",
  "userID": 12,
  "partB": "bar",
}

In addition to adding new properties, each layer can also exclude keys from JSON serialization, add aliases for keys (thus allowing mobiles to send/fetch data using old_key, when we rename something to new_key), and probably a few other things I’m forgetting.

Conclusion

PHP is remarkably malleable. error_handlers can be used as a poor-man’s handler-bind (unlike exceptions, they run before the stack is unwound, but you’re stuck dispatching on regular expressions if you want more than one); scalar type hints can be provided as a library; and traits can be abused to provide a level of multiple inheritance well beyond what was intended. While this malleability is certainly handy, I miss writing code in a language that doesn’t require jumping through hoops to provide what feel like basic facilities. But I’m also incredibly glad I can draw from the well of ideas in Common Lisp and bring some of that into the lives of developers with less exposure to the fantastic facilities Lisp provides.

Bonus!

My employer is desperate for user feedback, and as such is offering a free eight week trial. So if you want to poke at stuff and mock me when things don’t work very well (my core areas are nutritional analysis for recipes and food-related search results), that’s a thing you can do.

If you're outside the US, I should warn you that we have a number of known bugs and shortcomings you're much more likely to hit (we use a US-based product database; searching for things outside ASCII doesn't work due to MySQL having columns marked as the wrong charset; and there's a lot of weirdness around time because most user times end up stored as unix timestamps). The two bugs will be fixed eventually, but since they're complicated and as the US is our target market they're not exactly at the top of the list.

Don't you just love it when people move to a new blog? I'd 301 redirect you if I could, but since I can't you'll have to click through to read comment count unavailable comments or leave your own.