On Frameworks

Building any non-trivial app, one of the toughest decisions to make is which development framework to base your work on. And there’s no way around this decision once you realize there’s no such thing as “not using a framework.”

Even if you’re just binding together 3rd party components, a framework will be born out of any development work, and it will have its own tradeoffs to consider.

  • Will it be documented?
  • Will it be tested?
  • Will it have a community of people working on/within it?
  • Will it have a plugin architecture encouraging code reuse?
  • Will you have access to plugins written by people outside your team?
  • Will configuration be easy/reusable?
  • Will it address code/UX scenarios you hadn’t considered?
  • Will you get free bug fixes/features from outside developers?
  • Will it securely handle password and protection against XSS, CSRF, etc.?
  • Will other developers be able to jump into the project?

Developers, plugins, sub-frameworks, tools, and shops all form an ecosystem around a framework that tends to build value as it grows. A strong ecosystem can make up for product weaknesses; a trip through the Drupal and WordPress codebases will have some seasoned developers shuddering at some architectural choices made (long ago), yet that code runs great due to the work of tons of people over time. And, thanks to the wealth of plugins available, and to the continual transfer of knowledge from one developer to the next, devs who are experienced on those platforms can build impressive systems quickly.

On the flip side, there are properties of mature frameworks that are important to consider:

  • They can be slow to change, which may mean maintaining a separate git branch with your own fixes.
  • They rarely bend to support the use cases of individual sites.
  • They tend to have older code that may be harder to integrate with the latest practices.
  • They can be large; any framework that solves a lot of problems out-of-the-box will be. Microframeworks can be a great choice, but their value tends to be limited to plumbing.

Thankfully the ideal framework needn’t be chosen first. You may be better off prototyping something as quickly as possible—by any means—then rebuilding after the requirements are clearer. The danger is the temptation to ship prototypes as production systems, where they grow to become liabilities over time.

Dependency Injection: Ask For What You Need

Despite the scary name, the concept is simple: Your class or function should ask for dependencies upfront. It should not reach out for them. This gives you a few powerful advantages:

1. In unit tests you can pass in mock dependencies to verify/fake behavior.

Imagine your class depends on a database. You really don’t want to require a live database to run your tests, but also you want to be able to test a variety of responses from the database without running a bunch of setup queries. What if your logic depends on the time being around 3AM? You can’t reliably test this if your object pulls time from the environment.

2. Your API doesn’t lie to users about what’s really required to use it.

Imagine if you started cooking a recipe and step 7 read, “Go buy 10 mangos now.” Imagine a Skydive class whose jump() method waited 10 seconds then executed Backpack.getInstance().getParachute.deploy(). “Umm, I’m in the air and the Skydive class didn’t tell me I’d need a backpack…”. Skydive should have required a parachute in the constructor.

3. Your API behaves more predictably.

Imagine a function getNumDays(month). If I pass in February, I usually get 28, but sometimes 29! This is because there’s a hidden dependency on the current year. This function would be useless for processing old data.

Baking the dependencies in

Note that the same principles apply to functions (fine for this exercise, but you should avoid global functions/static methods for all sorts of reasons). Consider this function for baking peanut butter cookies:

function makePBCookies(AlbertsonsPB $pb) {
  // ... 20 lines of setup code
  $egg = new LargePublixEgg();
  $sugar = new DixieSugar('1 cup');
  $chef = Yelp::find('chef');
  // create an oven
  // mix and bake for 10 min
  return $cookies;
}

From the argument list, it isn’t clear you’ll need a large Publix egg on hand. What if you don’t have a Publix in your area? What if you want less sugary cookies? Let’s refactor:

function makePBCookies(Egg $egg, Sugar $sugar, PB $pb) {
  // ... 20 lines of setup code
  $chef = Yelp::find('chef');
  // create an oven
  // mix and bake for 10 min
  return $cookies;
}

Now it’s immediately clear at the top what ingredients you’ll need; you can use any brands you want; and you can even change amounts/sizes to yield all kinds of flavors. This is really flexible, but we can make it even better:

function makePBCookies(Egg $egg, Sugar $sugar, PB $pb, Oven $oven, Chef $chef) {
  $mix = $chef->mix(array($egg, $sugar, $pb));
  return $chef->bake($oven, $mix);
}

In case it wasn’t obvious, it’s now clear we’ll need a chef and oven, and it makes good sense to outsource the oven design because this logic isn’t really specific to peanut butter cookies. A sign that our refactoring is going well is that the function body is starting to read more like a narrative.

Let’s build the ultimate cookie-making function:

function makeCookies(BakeList $list, Chef $chef, Oven $oven, Decorations $decs = null) {
  // BakeList is a composite of recipe & ingredients
  $mix = $chef->mix($list->getIngredients(), $list->getRecipe());
  $cookies = $chef->bake($oven, $mix);
  if ($decs) {
    $cookies = $chef->decorate($cookies, $decs);
  }
  return $cookies;
}

We’ve refactored into several easy-to-test components, each with a specific task. This function is also easy to test because we just need to verify how the dependencies are passed and what methods are called on them. If we wanted to go even further we might notice that cookies come out differently in Denver vs. NYC (there’s a hidden dependency on altitude).

But that’s all dependency injection is: asking for what you need and not relying on sniffing dependencies from the environment. It makes code more flexible, more reusable, and more testable. It’s awesome.

I highly recommend Miško Hevery’s 2008 talks about dependency injection and testability, which really solidified the concepts and their importance for me. [This is an improved version of an article I wrote around that time hosted elsewhere.]

Today’s kids have a few things left to tinker with

[Drafts clean out. This one from January]

Mark Pilgrim laments the slow eradication of Apple products to which the owner has full (and gratis) software/hardware access.

Anyone can develop [for the iPad]! All you need is a Mac, XCode, an iPhone “simulator,” and $99 for an auto-expiring developer certificate. The “developer certificate” is really a cryptographic key that (temporarily) allows you (slightly) elevated access to… your own computer.

In the comments he claims, “By 2015, I predict Apple will not sell any devices with root access.” It’s a fun post—reminding me of my days with the CoCo (I had 1 and 3)—but a bit dramatic. Mark and I were pretty privileged and few to have several hundred dollar (in the early ’80s!) computers for us to tinker on; my dad let me drill into and add a motherboard switch to my CoCo 1! My tinkering was more or less limited to BASIC as I never found out about other programming languages really until high school. I mean, I’d heard of EDTASM for assembly editing but I had no idea what that was about, and it was hard enough getting decent documentation for BASIC.

What can today’s kids tinker on? Well, just about everything with a CPU and a port. It’s getting hard to find devices for which you can’t mod/jailbreak or find open firmware for on the web. You can compile and run programs right on the damn web.

I agree with Mark that bad laws and update patches make too much of this kind of tinkering illegal/temporary, but c’mon. Apple will not lead to a future where kids have no computers to experiment on. Yes, few iPad users will tinker, but in the past most kids didn’t have anything to tinker on at all.

Imagining Better E-mail

[Sitting in my drafts folder since August… Why not]

For building a clean and complete “paper trail” within a single message (which is irrefutably valuable in situations), top posting works great. For responding to individual sections, inline reply is great. Combining the two is generally a mess. In both top/inline models the manual management of quoted text in a text editor is pretty terrible. I posit that there’s no satisfactory solution to this multi-decade debate without a better UI than text editors provide. I’d like to see a reply process more like this:

  1. Highlight a selection for quoting. A reply form appears directly below with the cursor ready. (Commenting on a bill in OpenCongress is a bit like this.)
  2. Type the reply
  3. Repeat as necessary

Make the end points of each “quote” easily adjustable, and allow a preview to show you what the recipients would see, to allow you to reorder sections, to adjust header/footer sigs, etc.

A new message format based on git/hg could hold each previously referenced message in the thread, and with it the ability to walk back through the conversation, as well as embed cleanly the contact info of the senders, cryptographic signatures, etc.

The reader could chose to view the latest message in a variety of ways, including the traditional styles of plain text or HTML.

And you can’t fix e-mail without addressing sender authentication.

Perks of Life in the Kingdom of Nouns

Execution in the Kingdom of Nouns is one of Steve Yegge’s most entertaining posts about the verbosity and noun-centricity of Java (and other strongly typed languages without first-class functions). His post paints a picture of life outside JavaLand, where things are simpler and more straightforward:

There’s rarely any need in these kingdoms to create wrapper nouns to swaddle the verbs. They don’t have GarbageDisposalStrategy nouns, nor GarbageDisposalDestinationLocator nouns for finding your way to the garage, nor PostGarbageActionCallback nouns for putting you back on your couch. They just write the verbs to operate on the nouns lying around, and then have a master verb, take_out_garbage(), that springs the subtasks to action in just the right order.

With simplicity, there’s always a tradeoff. How does one test that take_out_garbage() actually works? You’ll need a full environment with real nouns lying around and all you can do is check the environment after completion. In the Kingdom of Nouns, you can pass in mock nouns and carefully watch what the function does with them. Maybe it’s important that the recycling gets separated, but if you only check the end environment, you won’t be able to tell it wasn’t.

What if trash day is moved to a different day? You might need a new take_out_garbage_wednesday(). As ridiculous as it seems, passing in a GarbageDestination makes the chore more flexible and testable. During testing I can pass in a destination of “right here”, saving me the hassle of creating an environment that includes the walkway out to the curb.

Whether you’re executing global/static functions or class methods, being able to pass dependencies in (where to find the trash, where it goes, when is it supposed to be there) not only makes your function more flexible, but more testable to boot.

This is not to suggest that Steve’s post was anti-dependency injection. I get the impression it was more a frustration of the expressive limitations of Java (when he wrote it—I think it has lambdas now). You can do dependency injection just fine without concrete classes, of course, but you wouldn’t want someone to pass in an array of GPS coordinates when you really need an object that you could call getStreetAddress() on. Type hinting an AddressProvider in the argument would let end users know exactly what to pass in and let the compiler/runtime know not to even bother executing the function, because we don’t have what we need. Also type hinted arguments allow good IDEs to prevent you from making mistakes, or to autocomplete existing variables in scope matching that type.

A Zend Framework App in a Single File

Most PHP micro-frameworks I’ve reviewed have some major cons: incomplete namespacing of functions/classes/global vars; doing too much/little; being under-tested; and the worst: forcing a unique (and usually under-documented) code structure that will make it difficult to “graduate” an app into a more full-featured framework. It also seems silly to rely on “micro-optimized” code if performance isn’t your number one goal and you have well-tested libraries sitting around.

So over the weekend, as a proof of concept (and mostly to get better acquainted with ZF’s MVC implementation), I built some minimal classes allowing one to implement a “quick and dirty” Zend Framework MVC app in a single script, with the resulting abomination being relatively easy to convert to a full app. The README shows how such a script might look. Continue reading  

Minify update

Minify 2.1.4 is approaching release and will have several long-awaited features and hopefully easier configuration.

Looking towards version 2.2/3(?), I recently committed the beginnings of a complete refactoring of the Minify API. The goal is to have a more flexible and extensible design that can include plugins like LESS and maybe handle @imports on the server-side—I’m still mulling over how radically a plugin should be able to alter the overall processing of the request. A key to doing this is splitting plugins into at least two stages and allowing the first to influence the cache id, and possibly add more sources/processors. By asserting that the request’s cache id is stable after the first stage, you can serve requests from the cache most of the time without running the second stage (JSMin, calls to Closure Compiler API, etc.).

Another goal was to eliminate static/global state from all components and have each component independently testable, meaning refactoring out access to global state like request/$_SERVER vars, file access from controllers, etc. A bunch of new classes and interfaces (read: files) could mean a performance hit, but we will also add an internal URL cache so that most requests will not load the system at all. At most once every N seconds the full stack will be loaded in order to make sure the cache is up-to-date with file mtimes, etc., but most requests will hit a very minimal front controller that simply includes a pre-generated PHP script (sending the necessary headers and output) depending on query string and Accept-Encoding. In theory this should be absurdly fast (for PHP output anyway), but of course sticking a reverse proxy in front is always a better idea if you can.

There’s a lot of work to be done. I thought of the URL cache a little late so some of my earlier design decisions were based on performance, and they need to be revisited.

Elgg Core Proposal: New Table “entity_list_items”

[This proposal has been superseded with ElggCollection.]

As of Elgg 1.7.4 there’s no way to specify a specific list or ordering of entities for use in an elgg_get_entities query. E.g. one might want to implement:

  • A “featured items” list for a group or user widget. On a group page this could be implemented in “left” and “right” lists for better display control
  • “Sticky” entities in discussion lists, or any other object lists
  • A “favorites” list for each user

Continue reading