Monkey patching in PHP

Tuesday, June 22. 2010
Comments

I haven't really had the chance or time to play with PHP 5.3 until recently when Ubuntu 10.04 upgraded my local installations and kind of forced me to dive into it a little. And I'm also probably the last person on the planet to notice, but namespaces in PHP 5.3 allow you to monkey-patch core PHP code.

What's monkey patching?

So monkey patching is a technique to replace functions at runtime. One of the more common applications is stubbing (or mocking) code in unit tests. So for example mocking the response from a server allows you to run a unit test in absence of another external service. Thus making your test suite both more robust and possible bugs easier to squash.

Up until 5.3 monkey patching was not available in PHP — unless you used the runkit extension.

Other use cases are changing the behavior of code without directly forking it and maintaining a local copy, e.g. to add a feature or so or even to apply bug fixes without modifying the original code.

Example

Here's some example code.

<?php
namespace monkeypatch;

$str = 'your mom';

echo "This should eight, but it's not: " . strlen($str) . "\n"; // 6
echo "Now this should be really eight: " . \strlen($str) . "\n";

function strlen($str) {
    return 6;
}

The difference between strlen() and \strlen() is, that the first call uses the function we defined in the current namespace. Since using the namespace operator requires it to be the first thing in a file, all consecutive functions and classes are part of this namespace. If an equivalent is not available in the current namespace, it'll fall back to the parent namespace or root.

Other applications that come to mind would be fixing the parameter order in strstr() and in_array(), and similar! But of course I'm kidding and wouldn't suggest that really. :-)

Fin

That's all kids!

Wieso zum Teufel benutzt DU keine Versionskontrolle?

Tuesday, January 5. 2010
Comments

(This post is entirely in German, I'll see if I can translate this rant later.) Also, Prost und frohes Neujahr — ich starte das neue Jahr damit etwas emotionalen Ballast aus dem alten Jahr loszuwerden!

Ab und an treffe ich wieder auf Kunden und Kollegen mit denen ich vor relativ langer Zeit — fünf oder sechs Jahren oder länger — zusammengearbeitet habe.

Die Zeitspanne ist deshalb wichtig weil ich generell daran Interesse habe immer wieder oder zumindest des öfteren mit jemandem zusammenzuarbeiten, wenn die Zusammenarbeit erfolgreich war. Wenn es allerdings Zwangspausen zwischen Projekten gibt, dann kann sich der geneigte Leser vorstellen, dass das letzte Projekt nicht vollkommene Zufriedenheit auf beiden Seiten ausgelöst hat.

Nichts desto trotz gibt jeder dem anderen eine neue Chance, und die Bezahlung spielt dann nicht eine gerade untergeordnete Rolle. Einige nennen so etwas Schmerzensgeld, und so ähnlich ging es mir auch in diesem Fall. Bzw. waren meine Motivation Weihnachtsgeschenke für Familie und Freunde, eine PS3 Slim und diverse andere Annehmlichkeiten.

Zwischenmenschliche Beziehungen

Schlußendlich entwickeln Menschen sich immer weiter. Diese Entwicklung merke ich nicht nur an technischen Fähigkeiten und Details, sondern auch menschlich, oder wie heisst so schön — am Stil.

Wenn ich mir nicht sicher bin, dann stelle ich mir folgende Fragen:

  • Wie laufen die Projekte ab?
  • Wieviel Spass macht es allen beteiligten?

Ausnahmen bestätigen die Regel und ab und an dauert die Entwicklung länger und ich muss Überzeugungsarbeit leisten.

In solchen Situation höre ich Sätze wie zum Beispiel:

  • "Aber das mach ich schon immer so."
  • "Objekte, wozu soll das gut sein? Kannst mir auch nen Array geben?!"
  • "Tests. Sowas mach ich nicht."

… oder mein absoluter Lieblingssatz:

  • "Versionskontrolle — das brauch ICH nicht."

Und irgendwann geht's natürlich schief.

Die Versionskontrolle

Besonders der letzte Satz hat es mir angetan und mich tatsächlich nach zwei Wochen Urlaub, nach denen mich wirklich nichts erschüttern konnte, während der Feiertage etwas auf die Palme gebracht.

Denn natürlich lief das Projekt nicht ganz so zügig und wurde nicht pünktlich zu Weihnachten fertig. Und da im neuen Jahr alles funktionieren soll, wurde es etwas hektisch!

Auf meine Frage welche (nicht ob) Versionskontrolle er benutze, erklärte mir der Kollege am Anfang ganz stolz, dass er alle Daten in mehren Kopien vorhät. Beim Kunden ("Produktivsystem") und auf seinen beiden Rechnern. Natürlich fällt einem dabei auf, dass die Versionskontrolle etwas missverstanden wird — denn primär geht es nicht um Backup.

Aber wieso man diesen Stress macht und nicht an einen Dienstleister wie github oder unfuddle auslagert, das ist mir ein Rätsel. Denn natürlich sollte auch die Versionskontrolle gesichert werden.

In dieser Situation fragte ich mich nur wie ein Team zusammenarbeitet, wenn es ohne VCS auskommen muss. Inzwischen kann ich es mir eigentlich gar nicht mehr vorstellen.

Als Argumente für den Einsatz einer Versionskontrolle führte ich an, dass es (eigentlich auch allein Sinn macht — Dokumentationszwecke — und) ab zwei Arbeitern nicht nur viele Vorteile mitsichbringt sondern ein Muss ist, und eine Voraussetzung dafür, dass ich an diesem Spiel teilnehme.

Ich erinnere mich oft an Projekte in dem Mitglieder des Teams mehr als einmal den Stand des anderen überschrieben haben. Für mich reicht das, aber anscheinend ist so etwas nicht abschreckend genug. Zu oft müssen Entwickler mit Code umgehen und wissen nicht wieso ein Problem auf diese und nicht jene Art gelöst wurde — bei richtigem Einsatz der Versionskontrolle (und Dokumentation im Code) passiert so etwas nicht.

Am Ende einigten wir uns auf git und ich kaufte dafür bei Github ein — und es ging los.

Im Projekt

Rückschläge gab es.

Mein Kollege besitzt zum Beispiel noch das selbe Notebook wie vor sechs Jahren. Und das hatte er gerade mit Windows XP neu eingerichtet. Und Git unter Windows war ihm zu mächtig ("das schreibt sich sicherlich überall in die Registry rein") wodurch er auch nie die Versionskontrolle dabei hatte.

Obwohl ich ihn mehr als einmal gebeten habe zumindest während unserer Zusammenarbeit git auf seinem Laptop aufzusetzen, hat er es dann doch nicht geschafft.

Besonders zeitraubend ist es, wenn der aktuelle Stand per Email oder per USB-Stick ausgetauscht wird. Manuelles mergen gehört zu den Dingen die ich überhaupt nicht machen möchte und generell lehne ich es auch ab meine geänderten Dateien per Email wieder zurückschicken.

Wieso auch, wenn alles mit git commit, git push und git pull erledigt werden kann?

Aber natürlich haben wir genau diese Dinge zwischen Weihnachten und Neujahr getan.

Die Ironie und Absurdität dieser Situation ist bezeichnend.

Fazit

Liebe Kinder!

Bei der Arbeit könnt Ihr wirklich am meisten Zeit vergeuden und alle in den Wahnsinn treiben wenn Ihr keine Versionskontrolle einsetzt.

Denn bei konsequenter und halbwegs gescheiter Benutzung würden folgende Fragen entfallen:

  • "Wieso sieht das so aus?"
  • "Hatten wir das nicht schon mal?"
  • "Welche Dateien hast Du gerade bearbeitet?".
  • "Kannst Du mir das mal eben schicken?"
  • "Das hab ich doch gestern schon gemacht?"
  • "Hast Du eben die Datei x überschrieben?"

... und mir würden noch andere einfallen, aber irgendwann muss auch mal Schluß sein.

The End

Keine Versionskontrolle — das hab ich lange nicht erlebt aber vielleicht ist das bezeichnend für die PHP-Welt. Ich würde auch zu gern noch einen Absatz über's Testen schreiben, denn auch darauf haben wir konsequent verzichtet.

Und es gab zu viele gute Beispiele wo es sinnvoll gewesen wäre. Aber das hebe ich mir für einen anderen Tag auf! :-)

Small notes on CouchDB's views

Wednesday, October 21. 2009
Comments

I've been wrestling with a couple views in CouchDB currently. This blog post serves as mental note to myself, and hopefully to others. As I write this, i'm using 0.9.1 and 0.10.0 in a production setup.

Here's the environment:

  • Amazon AWS L Instance (ami-eef61587)
  • Ubuntu 9.04 (Jaunty)
  • CouchDB 0.9.1 and 0.10.0
  • database size: 199.8 GB
  • documents: 157408793

On to the tips

These are some small pointers which I gathered by reading different sources (wiki, mailing list, IRC, blog posts, Jan ...). All those revolve around views and what not with a relatively large data set.

Do you want the speed?

Building a view on a database of this magnitude will take a while.

In the beginning I estimated about week and a half. And it really took that long.

Things to consider, always:

  • upgrade to trunk ;-) (or e.g. to 0.10.x)
  • view building is CPU-bound which leads us to MOAR hardware — a larger instance

The bottom line is, "Patience (really) is a virtue!". :-)

A side-note on upgrading: Double-check that upgrading doesn't require you to rebuild the views. That is, unless you got time.

View basics

When we initially tested if CouchDB was made for us we started off with a bunch off emit(doc.foo, doc)-like map functions in (sometimes) temporary views. On the production data, there are a few gotcha's.

First off — the obvious: temporary views are slow.

Back to JavaScript

Emitting the complete document will force CouchDB to duplicate data in the index which in return needs more space and also makes view building a little slower. Instead it's suggested to always emit(doc.foo, null) and then POST with multiple keys in the body to retrieve the documents.

Reads are cheap, and if not, get a cache.

doc._id

In case you wonder why I don't do emit(doc.foo, doc._id)? Well, that's because CouchDB is already kind enough to retrieve the document's ID anyway. (Sweet, no?)

include_docs

Sort of related, CouchDB has a ?include_docs=true parameter.

This is really convenient — especially when you develop the application.

I gathered from various sources that using them bears a performance penalty. The reason is that include_docs issues another b-tree lookup for every row returned in the initial result. Especially with larger sets, this may turn into a bottleneck, while it can be considered OK with smaller result sets.

As always — don't forget that HTTP itself is relatively cheap and a single POST request with multiple keys (e.g. document IDs) in the body is likely not the bottleneck of your operation — compared to everything else.

And if you really need to optimize that part, there's always caching. :-)

Need a little more?

Especially when documents of different types are stored into the same database (Oh, the beauty of document oriented storage!), one should consider the following map-example:

if (doc.foo) {
    emit(doc.foo, null)
}

.foo is obviously an attribute in the document.

JavaScript vs. Erlang

sum(), I haven't found too many of these — but with version 0.10+, the CouchDB folks implemented a couple JavaScript functions in Erlang, which is an easy replacement and adds a little speed on top. :-) So in this case, use _sum.

Compact

Compact, I learned, knows how to resume. So even if you kill the process, it'll manage to resume where it left off before.

When you populate a database through bulk writes, the gain from a compact is relatively small and is probably neglectable. Especially because compacting a database takes a long while. Keep in mind that compaction is disk-bound, which is often one of the final and inevitable bottlenecks in many environments. Unless hardware is designed ground up, this will most likely suck.

Compaction can have a larger impact when documents are written one by one to a database, or a lot of updates have been committed on the set.

I remember that when I build another set with 20 million documents one by one, I ended up with a database size of 60 GB. After I compacted the database, the size dropped to 20 GB. I don't have the numbers on read speed and what not, but it also felt more speedy. ;-)

Fin

That'd be it. More next time!

A case for PEAR and PHP4 (Or, why BC is important!)

Tuesday, September 22. 2009
Comments

Every once in someone likes to argue that PEAR is all fugly PHP4 code and why you should not use it, and instead go and use another framework or component library. Most of those people also say that they looked at or used PEAR x years ago and then act all surprised when someone else disagrees.

In related (BC) news, most people probably read my blog because of Zend Framework, and I remember that one of the reasons I sold my clients on Zend Framework was a supposedly backward compatibility and clean API. Well, a couple years later one knows it's not all that and since another BC break was argued today on one of the mailing lists and the project lead said I spread fud, I felt l needed to write something on the topic.

Facts first.

A small history of PEAR.

I don't know how old exactly PEAR is, but the manual is copyrighted since 2001 and none of the other current frameworks have been around eight — almost nine — years.

Because PEAR has been around much longer, we also have more older code than any of those PHP5-only frameworks. In comparison, Zend Framework's first stable was release in June, 2007, almost six years later.

Major versus minor releases.

A package' version consists of x.y.z.

The rules are as follow:

  • A BC break (see below) — increment x, and set y and z to 0.
  • Adding a new feature — keep x, increment y and set z to 0.
  • Fixing a bug — keep x and y, but increment z.

When someone refers to a major release in PEAR's context (and a lot of other projects such as Zend Framework, Solar and ezComponents follow this), it's one with a change in x. :-)

What is backward compatibility?

Backward compatibility, or BC, describes that a component, package or library preserves compatibility with an older versions.

Because programming itself and developers tend to evolve, PEAR tries to keep BC in all minor versions, but allows you to break compatibility to an earlier version with a new major release.

The exception to the rule is that you may break BC during alpha and beta releases before the package reaches a stable 1.0.0. Once a 1.0.0 is reached, BC may not be broken — for whatever reason.

PHP4?

Because PEAR aims to provide BC all the way, BC includes the PHP version when the package was first released. Which in turn means that of course you may make the code compatible to a later PHP release, but not without breaking compatibility to the initial release.

If you followed the above, you understand the reason why for example there is a Mail_Queue and (a soon to be) Mail_Queue2, or more importantly: why the Mail_Queue release in 2009 is still compatible to PHP4. Even though PHP4 EOL'd a while ago.

The first Mail_Queue package was released in September of 2002, the 1.0.0 stable release followed in December of the same year. Because its 1.0.0 was compatible with PHP4, we keep it backwards compatible with PHP4 until we release Mail_Queue2-0.1.0.

A principal

A lot of people argue that with the official end of life of PHP4, one should break BC anyway. But here is why you should not.

  • Even though we all love to use PHP5, there is still a lot of PHP4 in the enterprise. And like it or not, many of those apps use PEAR, and not your funky PHP5 framework.

  • How do you keep so-called necessary and unnecessary BC breaks apart? From another point of you (which is not your own), there is always a necessary BC break to fix implement something else.

  • Because there is no such thing as small or acceptable BC breaks. There are BC breaks or there are none, it's one of those things that is black and white.

BC in other frameworks

I know for a fact that ezComponents is very strict on BC. I cannot comment on Solar or Symfony, but at least in Solar's case, I'm assuming that adhere to BC as well since a some former PEAR developers are active and they also follow the PEAR Coding Standard in many respects.

Zend Framework?

A friend of mine said that if Zend Framework really kept BC, we would at 10.0.0 and not on 1.9.3.

Reasons why Zend Framework likes to break BC, even though it advertises full BC:

  • No versioning per components but per framework.

  • Missing peer review and QA leads to unstable code in a so-called stable release. (Which in turn also fakes the stability of the entire framework since it suggests that a component that was added a couple weeks ago is as stable as a component added in 2007.)

  • Because it fixes an "issue". (Biggest WTF of them all.)

The issue in question, I'm not even sure what they were trying to fix. Supposedly some developers found it too hard or did not understand how to write an adapter for Zend_Db and someone committed a fix in the 1.9 tree/branch and apparently it was OK to break BC because it was the easier way out.

I haven't updated some projects since late 1.8.x because of these BC breaks because no one can tell me what the issue is and I don't have a day to debug my application to figure out where and how it breaks. This is annoying as hell, especially since they are supposed to be tailored to the business.

On a side-note, I know of a couple components (e.g. Zend_Session) which really deserve (!) a BC break and don't get one until 2.0. And I totally get why, but why is it OK in some cases? All BC breaks fix issues!

(Btw, as I finish this post, I see an email to zf-contributor@ in my inbox where someone considers pulling the 1.9.3 release (because it obviously breaks BC). Guess I didn't spread that much FUD after all.)

PHP in schnell

Thursday, September 3. 2009
Comments

Sorry, this is all in German. Or at least Germenglish. ;-) The slides are not rocket science and show a basic introduction to "faster PHP". Things to do, things to avoid, some autoloading and a little on "shared nothing" in the end. There are some speaker-notes included (link) to make the slides more valuable for those who couldn't make it.

Hier die Folien zu meinem Vortrag "PHP in schnell" bei der PHP Usergroup in Berlin im September 2009. Leider sieht man unten keine Notizen (speaker notes). Man kann sie jedoch sehen, wenn Ihr über folgenden Link (Actions > Show speaker notes (Vorsicht: Rechtschreibfehler usw. inklusive)) die Präsentation öffnet.

Wer Fragen hat, darf gerne kommentieren oder mich einladen. ;-)

Vielen Dank an alle die da waren. Und Danke an den NewThinking Store Berlin für den Ort, Beamer, Internet und das Glas Wasser. ;-)