The Log Book of Manuel Kiessling / Writings about Software Development and System Operation topics Sun, 06 May 2012 15:04:44 +0000 http://wordpress.org/?v=2.9.2 de hourly 1 Tutorial: Developing HTML5 Canvas Games for Facebook with JavaScript – Part 1 /2012/04/02/tutorial-developing-html5-canvas-games-for-facebook-with-javascript-part-1/ /2012/04/02/tutorial-developing-html5-canvas-games-for-facebook-with-javascript-part-1/#comments Mon, 02 Apr 2012 13:34:10 +0000 Manuel Kiessling /?p=533 This is a multi-part tutorial series. You are currently reading part 1.

Some days ago, my son asked me how computer games are made. He’s five years old and couldn’t quite imagine how games are created, because “you can’t just paint them like animation movies, can you?”.

I quickly realized that explaining it to a child is really difficult. And so I decided to create a game, with him as the Creative Director who decides what the game should be like.

The result is a simple yet fully-functional 2D space shooter, available on Facebook. This tutorial describes how to create the game using the HTML5 canvas element and JavaScript, and how to integrate it into Facebook.

I never did game development before, and for me, the two major takeaways from this experience are a) JavaScript/Canvas game development is much more simpler than you think, and b) Facebook integration actually is a lot of fun.

I mention the second point because I always greeted Facebook development with smiles, but to be honest, it’s a very pleasing experience, and the whole social graph thing makes a lot of sense for games.

But let’s talk about game development first. As said, it was way simpler than I thought – in fact, being the old web developer that I am, I always deemed it to be black art. Turned out, it’s not difficult, it’s just completely different – and therefore only seems difficult.

When developing web services, you are used to think in terms of request and response, stateless connections, model-view-controller… – game development takes place in a completely different context.

When looking at games, I always thought “there is so much happening at the same time, so many objects interacting with each other – how do you develop code for this without ending up with a chaotic mess?”.

The most important thing to understand was the concept of the game loop, which lies at the heart of any action game: this loop continuously cycles through two steps: update and draw.

And from a high-level perspective, both steps are very simple: update just takes every game object and asks it to update its state, that is, it asks “coming from your current state, what will your state be in the next iteration of the game loop?”. Every object takes care of its own state and how to change its state when going from one game loop cycle to the next.

A very simple example is that of game object movement – let’s say you have a spaceship object with a certain state. Whenever this object is asked to update its state, it will set its position within the game world to new values, using a certain algorithm – e.g., it could have a horizontal speed value and a vertical speed value, which is the number of pixels the object moves within the game world in horizontal and vertical direction during one loop cycle.

Thus, when the spaceship object is asked to update its state, it adds the value of its horizontal speed to its horizontal position, and the value of its vertical speed to its vertical position – this is all. Because this is done every game loop cycle, the result is a moving spaceship.

Of course, the internal state of game objects might be influenced by external events – e.g., the player’s spaceship should only move if the user presses the arrow keys on his or her keyboard, and should only shoot whenever the space bar is pressed. These external events are delegated to the game object and handled there.

A third type of update logic is that of object interactions – for our game, it’s all about object collisions: did a bullet hit an enemy? Did the player’s spaceship collide with an enemy ship? The collision logic triggers certain events within the affected game objects – e.g., if the collision logic detects that an enemy is hit by a bullet from the player’s ship, it triggers the beenHit() method on that enemy. This, in turn, is just another external event which results in the enemy object changing its internal state – e.g. triggering the explosion of that enemy, or just lowering its life-points by 1; whatever the game rules are that you decide to implement.

The second step of every loop cycle is the draw step. This one is even simpler: in every loop cycle, the screen is cleared, and the application cycles through every single game object and asks it to draw itself. Because objects have changed their internal state in the update step, their position (or color, or size, or orientation) has probably changed, and they are drawn at a different position than in the previous loop cycle. This results in the illusion of object movement.

How often does the application cycle through the update->draw cycle? That’s simple – if your game runs at 60 frames per second, update and draw are called 60 times per second. And that is all.

Let’s wrap this up with some example (and pseudo) code. Let’s say we have a game world that exists of only two game objects – a spaceship and a bullet.

When the game starts, the spaceship is in the upper left corner of the world, and the bullet is at the very bottom of the world, at the horizontal center:

--------------------------------------------------------- | | | P | | | | | | | | | | | | | | | | B | ---------------------------------------------------------

Where does the “world” actually come from? We will talk about that in a moment, let’s keep the discussion abstract for now.

When thinking about placing and moving objects in a 2D world, you need some kind of coordinate system. Let’s say the horizontal axis of our world is called x and measured from 0 (left end of the world) to 54 (right end of the world), and the vertical axis is called y and measured from 0 (upper end of the world) to 9 (bottom end of the world).

In this system, the Player P is currently located at x: 3 and y: 1, and the bullet is at position x: 27, y: 9:

0123456789012345678901234567890123456789012345678901234 x → --------------------------------------------------------- 0| | 1| P | 2| | 3| | 4| | 5| | 6| | 7| | 8| | 9| B | --------------------------------------------------------- y ↓

These x and y coordinates are the first and most fundamental attributes that make up the current state of each game object. We will later implement these as simple numerical attributes of the objects in our application that represent game objects.

Ok, so our game objects have a basic state represented by their position coordinates. We want our objects to move when the game is running, or in our game programming lingo: we want their positional values to be altered when cycling through the update loop.

How could this be implemented? As said, the game update loop iterates over the list of all game objects and calls their update method. Thus, the update method of the Player object is the place where the logic that alters the x and y value of this object should be implemented. The same applies to the Bullet object, respectively.

For now, let’s ignore the fact that the player’s object should be steered by keystrokes. It just moves on it’s own using a very simple algorithm, implemented in its update method.

What could this algorithm look like? Again, we keep it extremely simple for now. Let’s add two other attributes to each game object: xVelocity and yVelocity. They are the parameters for our incredibly sophisticated algorithm: xVelocity is the amount of pixels that the game object moves on the x-axis, and yVelocity – well, you get the idea. Here is the pseudo-code for the player object which starts at position x: 3, y: 1 and moves from the upper left corner of the game world to its lower right corner, one pixel per loop cycle:

Player = { x: 3 y: 1 xVelocity: 1 yVelocity: 1 update = function() { x = x + xVelocity y = y + yVelocity } }

And that’s it. The game, running at, say, 60 frames per seconds, asks the Player object 60 times per second to update() itself, resulting in a player moving diagonally across the screen. That is, if we implement some draw logic:

Player = { x: 3 y: 1 xVelocity: 1 yVelocity: 1 symbol: 'P' update = function() { x = x + xVelocity y = y + yVelocity } draw = function() { drawAtPosition(x, y, symbol); } }

After asking all game objects to update themselves, the game loop asks them to draw themselves – update->draw->update->draw->update->draw… and so on.

Let me give you an idea of how the final game will look like:

The game world is a 740 x 640 pixel canvas. The screenshot shows 5 game objects:

  • A terrain tile
  • The player’s spaceship
  • 2 bullets shot by the player, flying upwards
  • An enemy (which is likely to be hit by the bullets in a moment)

Remember, from the game loop point of view, these objects are all treated same: in every loop cycle, each one is asked to update itself, and then each one is asked to draw itself. In every loop cycle, the update method of the terrain tile moves the tile one pixel downwards (resulting in a scroll effect), the player’s ship is moved on the x and y axis depending on the arrow keys the player presses, the bullets simply fly upwards with the speed defined in their yVelocity attribute, and the enemy ship is changing its x and y position values depending on some randomized algorithm (simply to make its movements more interesting than just moving in a straight line). If the player presses the space key, a new bullet object is created and inserted into the game world, and if a bullet objects collides with an enemy object, the enemy object and bullet object disappear (sorry, explosions do not fall within the scope of this document).

We will need to write quite some code for these mechanics to work, but at least the GFX part is dead simple: every game object on this screenshot is simply represented with a PNG image. Thanks to PNG’s alpha transparency, it’s very simple to draw the game world by drawing the image for each game object on top of each other: first the screen is cleared, then the terrain tile is drawn, then the enemy, then the bullets, then the player. The shadows of the player and enemy ship are nothing special – they are simply part of the PNG with the player’s ship and enemy ship, respectively, and are transparent by using the alpha channel of the images:

Well then, let’s get our hands dirty, and let’s start where every journey begins: at index.html.

Open your favorite editor and create a simple HTML page that provides the canvas element for our game world:

/index.html <!DOCTYPE html> <html> <head></head> <body> <canvas id="world" width="740" height="640"> This browser can not run this game (canvas support missing). </canvas> </body> </html>

Now that we talked about the game loop again and again, let’s finally create it. Not surprisingly, it’s a piece of JavaScript code. As I don’t like these “let’s put all our code into one single file because that’s so much simpler” tutorials, we should think about where to put it. How about representing the game with an object that has the update and draw cycles as methods, and starts the game loop that iterates through these cycles? We could put these into a Game constructor, in a file named Game.js.

I suggest we put this file in a lib subfolder, which itself is a subfolder of scripts. This way, we keep the different concerns of our application neatly separated. HTML files live at the root, all JavaScript goes into scripts, which in turn will be separated into lib for the building blocks of the game itself, app for the JavaScript files that relate to the HTML files (thus, the script code for /index.html will be in /scripts/app/index.js), and vendor for external libraries.

But let’s not get ahead of outselves – what we need now is the constructor for the main game object:

/scripts/lib/Game.js var Game = function() { this.fps = 60; var game = this; var gameloop = setInterval(function() { game.updateAll(); game.drawAll(); }, 1000 / this.fps); } Game.prototype.updateAll = function() { // } Game.prototype.drawAll = function() { // }

Actually, this already creates a running game – with the minor restraint that the game world is completely empty, and no action takes place.

Let’s quickly fill the world so we can experience the pleasure of seeing something on the screen.

We need at least one game object which is able to at least draw itself. We will solve this by providing a very basic player.

The player is represented by its own object. Let’s create a constructor for it:

/scripts/lib/Player.js var Player = function(game) { this.game = game; this.x = 100; this.y = 100; } Player.prototype.update = function() { // } Player.prototype.draw = function() { this.game.drawRectangle('#f00', this.x, this.y, 10, 10); }

Like any other game object, the player object needs an update and a draw function. These will be called by the master game object on every cycle.

Our player doesn’t do anything yet, therefore its update method is empty, but it knows how to draw itself – by drawing a red 10 x 10 pixel rectangle into the gameworld, at its current position.

However, we don’t want to hardwire the low level canvas drawing logic into our game objects – therefore, we pass the game object into the player’s constructor, and call the appropriate drawing method on the game object. This way, the actual drawing can be handled outside the game objects, and inside the main game object.

This means we need to actually pass the game object into our player object when we create it. This is done in the Game constructor. Let’s also add the update and drawing calls to our player to the game loop:

/scripts/lib/Game.js var Game = function() { this.fps = 60; this.player = new Player(this); var game = this; var gameloop = setInterval(function() { game.updateAll(); game.drawAll(); }, 1000 / this.fps); } Game.prototype.updateAll = function() { this.player.update(); } Game.prototype.drawAll = function() { this.player.draw(); } Game.prototype.drawRectangle = function() { // }

Well, this still won’t put any pixels on our screen, of course. We have the <canvas> element in our index.html file, and we want to draw into it from our JavaScript code in Game.js – it’s time to put some code into place which brings both together.

Technically, you don’t draw into a canvas directly. In JavaScript, you ask the canvas element for a context, which gives you an object that provides several draw methods, like this:

var context = document.getElementById('myCanvas').getContext('2d'); context.fillStyle = '#f00'; context.fillRect(5, 10, 90, 20);

This would draw a red rectangle onto the canvas element with ID myCanvas, with the upper left corner 5 pixels from the left and 10 pixels from the top of the canvas, a width of 90 pixels, and 20 pixels high.

We need to get the 2D context of our world canvas in index.html, and implement the actual drawRectangle functionality:

/scripts/lib/Game.js var Game = function() { this.fps = 60; var canvas = document.getElementById('world'); this.context = canvas.getContext('2d'); this.player = new Player(this); var game = this; var gameloop = setInterval(function() { game.updateAll(); game.drawAll(); }, 1000 / this.fps); } Game.prototype.updateAll = function() { this.player.update(); } Game.prototype.drawAll = function() { this.player.draw(); } Game.prototype.drawRectangle = function(color, x, y, width, height) { this.context.fillStyle = color; this.context.fillRect(x, y, width, height); }

Now we can wire everything together in our index.html and see our player for the first time:

/index.html <!DOCTYPE html> <html> <head> <script type="text/javascript" src="scripts/lib/Game.js"></script> <script type="text/javascript" src="scripts/lib/Player.js"></script> </head> <body> <canvas id="world" width="740" height="640"> This browser can not run this game (canvas support missing). </canvas> <script type="text/javascript"> var game = new Game(); </script> </body> </html>

Now if you open the index.html file in your browser, you see a red square. Isn’t it beautiful?

Ok, let’s add a tad of action, and make our player move across the screen:

/scripts/lib/Player.js var Player = function(game) { this.game = game; this.x = 100; this.y = 100; } Player.prototype.update = function() { this.x += 1; this.y += 1; } Player.prototype.draw = function() { this.game.drawRectangle('#f00', this.x, this.y, 10, 10); }

Reload and enjoy – but wait, what’s that? Instead of moving square, we see a bold red line being drawn over the screen. That’s because the canvas doesn’t know about our game loop – it does not know that on every loop cycle, the screen needs to be completely redrawn; it just draws everything we ask it to draw on top of each other.

This can be easily fixed. At the start of each loop cycle, we will simply fill the full canvas with one large white rectangle:

/scripts/lib/Game.js var Game = function() { this.fps = 60; var canvas = document.getElementById('world'); this.context = canvas.getContext('2d'); this.context_width = canvas.width; this.context_height = canvas.height; this.player = new Player(this); var game = this; var gameloop = setInterval(function() { game.updateAll(); game.drawAll(); }, 1000 / this.fps); } Game.prototype.updateAll = function() { this.player.update(); } Game.prototype.drawAll = function() { this.drawRectangle('#fff', 0, 0, this.context_width, this.context_height); this.player.draw(); } Game.prototype.drawRectangle = function(color, x, y, width, height) { this.context.fillStyle = color; this.context.fillRect(x, y, width, height); }

Refresh your browser, and you will see a moving red square. First achievement unlocked!

That’s it for today. Part 2 of this tutorial series will introduce the concept of steering our player with the arrow keys, and other goodies.

You can browse the code of part 1 at https://github.com/ManuelKiessling/ HTML5CanvasJavaScriptFacebookTutorialCode/tree/part1.

]]>
/2012/04/02/tutorial-developing-html5-canvas-games-for-facebook-with-javascript-part-1/feed/ 0
“We need to work longer” – Why this is not what you want to say /2012/04/02/we-need-to-work-longer-why-this-is-not-what-you-want-to-say/ /2012/04/02/we-need-to-work-longer-why-this-is-not-what-you-want-to-say/#comments Mon, 02 Apr 2012 12:32:21 +0000 Manuel Kiessling /?p=333 Every now and then, a manager at your company might say something like “We need to work longer” or “Our people need to work longer”.

Here’s why I don’t think it is a good idea to say this.

Well, first of all, there may really be the need for people to change something about their work, and so the motivation and the goal of the manager might be valid and important.

However, if the manager puts emphasis on people working longer, he probably won’t achieve his goal. Why? Because his real goal is not that people actually work longer – but he doesn’t actually know this. We’ll see why in a moment.

Ok, now if you’re telling people you want them to work longer, what are you really telling them? You are telling them this:

“Look, you’re working about 8 hours per day now, but I want you to work 9, 10 or 11 hours, because we need to become better. So, I’m asking you to work 3 hours more, which means I want you to do around 30% more work, which means I want us as a company to become around 30% better.”

30%? Really? That’s the amount of how much you want us to do better? And all we have to do is stay longer, and that’s it?

Let’s face it, doing about 30% better isn’t going to get you anywhere significant. And I’m not even going to start talking about why working 30% longer of course won’t bring anything significant in your company up by 30%, especially not the “doing better” – much has been written about this already.

Here is what I propose: Ask your people that you want them to become 300% better at what they do! That you want the whole company to become 300% better than it is right now. And don’t even mention working longer.

Because if you tell people this, then everybody is going to understand that this goal won’t be achieved by working 300% longer, because 8 x 3 is 24, and for obvious reasons this is not going to work out.

You should probably even go this far as to tell your people you want them to achieve the 300% goal by actually working normal 8 hour workdays – as a new, strict rule! Now this is an interesting challenge for intelligent people, isn’t it?

Because then they are forced to contemplate about how well they will need to work, and not how much they will need to work, because that is going to be the only way to achieve the goal.

At the end of the day, what you want is people to change, and that is the hardest thing of all. Maybe the only thing people hate even more than change is being critizised. Which is why it isn’t such a good idea to start with a negative connotation if you want people to change.

Why does asking people to work longer have a negative connotation? Because it sounds like a punishment. It sounds like “we haven’t been doing well, and as a result, we need to stay longer”. Well, at least in Germany, “staying longer” is exactly the kind of punishment we all have actually been raised with in school (it is called “Nachsitzen”).

Here is another point of view: What you actually want is people to become worthier for your company, that they create more value, right? Well, it seems obvious to me that some people in companies seem to already have partly achieved this goal, because they get paid a lot more than others. Which basically means that they create more value for the company (which is or at least should be the only valid reason they get paid more, right)?

So, let’s say you have some Juniors and some Seniors in your company, and the Seniors get paid twice the money compared to the Juniors.

How did the Seniors get there? Was it something like this?

  • As a Junior, they worked 5 hours
  • As a Regular, they worked 7 hours
  • As a Senior, they now work 10 hours
Well, I guess we can agree that this is not how this kind of stuff works.

But then what’s happening here? Why is it ok to pay them more? Well, those people don’t work longer, they work better. So, if this is what enables people to create more value for the company, then why would you want to put the focus on working longer?

The conclusion: Don’t ask people to work longer. Instead, think really hard about how to create an environment which allows people to work a lot better than they do today, and put a lot of effort into implementing this environment.

This of course is a lot harder than just asking them to work longer – but this is a very good sign that it is going to achieve you a lot more.

Manuel Kiessling is currently working at MyHammer AG, a company that puts a lot of effort into continuously improving by 300%.

]]>
/2012/04/02/we-need-to-work-longer-why-this-is-not-what-you-want-to-say/feed/ 0
True universal JavaScript modules with write-once-run-anywhere Jasmine specs /2012/03/30/true-universal-javascript-modules-with-write-once-run-anywhere-jasmine-specs/ /2012/03/30/true-universal-javascript-modules-with-write-once-run-anywhere-jasmine-specs/#comments Fri, 30 Mar 2012 08:06:43 +0000 Manuel Kiessling /?p=611 As a JavaScript developer writing general-purpose libraries, you probably wish you could go fully universal, that is, you might want to create a library:
  • that can be used in the browser and in Node.js – without any hacks for either platform, and without code-duplication
  • that transparently utilizes AMD via RequireJS in the browser and CommonJS via require in Node.js – without any hacks for either platform, and without code-duplication
  • with a Jasmine spec suite which runs in the browser and in Node.js – without any hacks for either platform, and without code-duplication

Turns out this is perfectly possible. Consider the following library structure:

lib/ multiply.js spec/ multiply.spec.js

As stated above: Without making use of any nasty hacks or duplicating any or all of our lib or spec code, we would like to be able to use our multiply.js module in a web-based browser application, or in a server-side application for Node.js – of course assuming that multiply.js provides a general-purpose functionality that is usable on both platforms, and not e.g. something working with a browser-DOM. In our example library, multiply provides a function that does the very useful job of multiplying two number, like this:

console.log(multiply(2, 5)); // outputs "10"

Furthermore, when using our lib in the browser, we would like to be able to load it using RequireJS, and when using it in a Node.js application, we would like to be able to require() and use it just like any other npm module:

// Browser script define("../lib/multiply", function(multiply) { console.log(multiply(2, 5)); });

// Node.js script var multiply = require("../lib/multiply.js"); console.log(multiply(2, 5));

And we want our Jasmine specification multiply.spec.js to be able to run in a web-based Jasmine runner as well as in a Node.js based runner, enabling us to test our library on both platforms. Again, without duplicating the spec or lib code.

All this can be achieved with the following steps:

  1. Export the lib module and its spec via RequireJS’ describe logic
  2. For Node.js, add the amdefine package to make the lib and its spec loadable via Node’s require()
  3. For Node.js, add the jasmine-node package (but no node-specific RequireJS implementation!)
  4. For the client-side, add Jasmine and RequireJS
  5. For the client-side, write a Jasmine SpecRunner that uses RequireJS’ describe() to load the spec files for the test run
  6. Once this is done, the library structure will look as follows:

    package.json lib/ multiply.js spec/ multiply.spec.js run.sh SpecRunner.html vendor/ require.js jasmine/ jasmine-html.js jasmine.css jasmine.js jasmine_favicon.png MIT.LICENSE

    The /package.json file is the place where the amdefine and jasmine-node dependecy for the Node.js environment will be defined, /spec/run.sh is the Jasmine runner for the Node.js environment, /spec/SpecRunner.html is the Jasmine runner for the client-side environment, and /vendor hosts the external libraries RequireJS and Jasmine, again for the client-side environment.

    Let’s tackle each file in turn:

    /package.json: { "name": "CafeGraph", "version": "0.0.1", "dependencies": { "amdefine": ">=0.0.2" }, "devDependencies": { "jasmine-node": "1.0.x" } }

    This states that the npm modules amdefine and jasmine-node are needed for our lib to work in the Node.js environment. Run npm install to have them automatically installed.

    /lib/multiply.js: if (typeof define !== 'function') { var define = require('amdefine')(module) } define([], function() { var multiply = function(a, b) { return a * b; }; return multiply; });

    Here, several things happen that are crucial for our library to be universal. Because the module itself is wrapped in RequireJS’ define() function, it need some special treatment to be usable within a Node.js context. This is what the first line does, it makes sure that Node.js uses the define function of the amdefine package. This way, the module becomes usable just like any other npm package, even though RequireJS is not available.

    The return multiply; statement has the same effect as module.exports = multiply; would have, making the multiply function available for Node.js scripts that do var multiply = require(“../lib/multiply.js”);

    /spec/multiply.spec.js: if (typeof define !== 'function') { var define = require('amdefine')(module) } define(["../lib/multiply.js"], function(multiply) { describe("multiply", function() { it("multiplies two numbers", function() { expect(multiply(2, 5)).toEqual(10); }); }); });

    /spec/run.sh: #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" node $DIR/../node_modules/jasmine-node/lib/jasmine-node/cli.js $DIR

    This just a script which enables me to run the Jasmine test suite for the Node.js environment via ./spec/run.sh on the command line. It’s probably a totally unnecessary hack, but I never really found the time to find a better solution. Recommendations welcome. Not part of our code, thus it’s acceptable for now I think.

    /spec/SpecRunner.html: <!DOCTYPE html> <html> <head> <title>Jasmine Test Runner</title> <!-- Jasmine --> <link rel="stylesheet" type="text/css" href="../vendor/jasmine/jasmine.css"/> <script type="text/javascript" src="../vendor/jasmine/jasmine.js"></script> <script type="text/javascript" src="../vendor/jasmine/jasmine-html.js"></script> <!-- RequireJS --> <script type="text/javascript" src="../vendor/require.js"></script> </head> <body> <script type="text/javascript"> require.config({ baseUrl: './' }); require([ '../spec/multiply.spec.js' ], function() { jasmine.getEnv().addReporter(new jasmine.TrivialReporter()); jasmine.getEnv().execute(); }); </script> </body> </html>

    The web-based Jasmine spec runner needs several modifications, because the spec files need to be require()d the RequireJS way. However, once this is set up, the workflow for adding new code and specs is straight-forward. For adding new specs to the Node.js spec run, no additional steps are necessary. To include new specs in the web-based spec run, simply add the path to the spec file to the require() array, and that’s it.

    You can find the complete library code on GitHub at https://github.com/ManuelKiessling/UniversalJavaScriptModulesExample, with some additional usage examples.

    tl;dr: Writing JavaScript modules that can be seamlessly included in client-side as well as server-side applications, and providing Jasmine test suites which allow to test these modules in a browser environment as well as a Node.js environment is possible without any dirty workarounds by writing these modules using the AMD pattern, and then using the amdefine package to make them available to Node.js.

    ]]> /2012/03/30/true-universal-javascript-modules-with-write-once-run-anywhere-jasmine-specs/feed/ 0 Talk: PHP 5.4 – die wichtigsten Neuerungen im Überblick /2012/03/24/talk-php-5-4-die-wichtigsten-neuerungen-im-ueberblick/ /2012/03/24/talk-php-5-4-die-wichtigsten-neuerungen-im-ueberblick/#comments Sat, 24 Mar 2012 21:42:30 +0000 Manuel Kiessling /?p=600 PHP 5.4 - die wichtigsten Neuerungen im Überblick gehalten. Folien und Videomitschnitt des Talks nach dem Klick.]]> Am 14. März 2012 fand das erste Treffen der Symfony User Group Berlin statt. Ich habe dort einen kurzen Talk mit dem Titel PHP 5.4 – die wichtigsten Neuerungen im Überblick gehalten. Die Folien des Talks gibt es hier zum Download als PDF und hier bei Slideshare. Einen Videomitschnitt gibt es bei Ustream.

    ]]>
    /2012/03/24/talk-php-5-4-die-wichtigsten-neuerungen-im-ueberblick/feed/ 0
    Object-orientation and inheritance in JavaScript: a comprehensive explanation /2012/03/23/object-orientation-and-inheritance-in-javascript-a-comprehensive-explanation/ /2012/03/23/object-orientation-and-inheritance-in-javascript-a-comprehensive-explanation/#comments Fri, 23 Mar 2012 09:43:26 +0000 Manuel Kiessling /?p=568 Let’s talk about object-orientation and inheritance in JavaScript.

    The good news is that it’s actually quite simple, but the bad news is that it works completely different than object-orientation in languages like C++, Java, Ruby, Python or PHP, making it not-quite-so simple to understand.

    But fear not, we are going to take it step by step.

    ]]>
    Let’s talk about object-orientation and inheritance in JavaScript.

    The good news is that it’s actually quite simple, but the bad news is that it works completely different than object-orientation in languages like C++, Java, Ruby, Python or PHP, making it not-quite-so simple to understand.

    But fear not, we are going to take it step by step.

    Blueprints versus finger-pointing

    Let’s start by looking at how "typical" object-oriented languages actually create objects.

    We are going to talk about an object called myCar. myCar is our bits-and-bytes representation of an incredibly simplified real world car. It could have attributes like color and weight, and methods like drive and honk.

    In a "real" application, myCar could be used to represent the car in a game which is driven by the player of that game – but we are going to completely ignore the context of this object, because we are going to talk about the nature and usage of this object in a more abstract way.

    If you would want to use this myCar object in, say, Java, you need to define the blueprint of this specific object first – this is what Java and most other object-oriented languages call a class.

    If you want to create the object myCar, you tell Java to "build a new object after the specification that is laid out in the class Car".

    The newly built object shares certain aspects with its blueprint. If you call the method honk on your object, like so:

    myCar.honk();

    the Java interpreter will go to the class of myCar and look up which code it actually needs to execute, which is defined in the honk method of class Car.

    Ok, nothing shockingly new here. Enter JavaScript.

    A classless society

    JavaScript does not have classes. But as in other languages, we would like to tell the interpreter that it should built our myCar object following a certain pattern or schema or blueprint – it would be quite tedious to create every car object from scratch, "manually" giving it the attributes and methods it needs every time we build it.

    If we were to create 30 car objects based on the Car class in Java, this object-class relationship provides us with 30 cars that are able to drive and honk without us having to write 30 drive and honk methods.

    How is this achieved in JavaScript? Instead of an object-class relationship, there is an object-object relationship.

    Where in Java our myCar, asked to honk, says "go look at this class over there, which is my blueprint, to find the code you need", JavaScript says "go look at that other object over there, which is my prototype, it has the code you are looking for".

    Building objects via an object-object relationship is called Prototype-based programming, versus Class-based programming used in more traditional languages like Java.

    Both are perfectly valid implementations of the object-oriented programming paradigm – it’s just two different approaches.

    Creating objects

    Let’s dive into code a bit, shall we? How could we set up our code in order to allow us to create our myCar object, ending up with an object that is a Car and can therefore honk and drive?

    Well, in the most simple sense, we can create our object completely from scratch, or ex nihilo if you prefer the boaster expression.

    It works like this:

    var myCar = {} myCar.honk = function() { console.log("honk honk"); } myCar.drive = function() { console.log("vrooom..."); }

    This gives us an object called myCar that is able to honk and drive:

    myCar.honk() // outputs "honk honk" myCar.drive() // outputs "vrooom..."

    However, if we were to create 30 cars this way, we would end up defining the honk and drive behaviour of every single one, something we said we want to avoid.

    In real life, if we made a living out of creating, say, pencils, and we don’t want to create every pencil individually by hand, then we would consider building a pencil-making machine, and have this machine create the pencils for us.

    After all, that’s what we implicitly do in a class-based language like Java – by defining a class Car, we get the car-maker for free:

    Car myCar = new Car();

    will built the myCar object for us based on the Car blueprint. Using the new keyword does all the magic for us.

    JavaScript, however, leaves the responsibility of building an object creator to us. Furthermore, it gives us a lot of freedom regarding the way we actually build our objects.

    In the most simple case, we can write a function which creates "plain" objects that are exactly like our "ex nihilo" object, and that don’t really share any behaviour – they just happen to roll out of the factory with the same behaviour copied onto every single one, if you want so.

    Or, we can write a special kind of function that not only creates our objects, but also does some behind-the-scenes magic which links the created objects with their creator. This allows for a true sharing of behaviour: functions that are available on all created objects point to a single implementation. If this function implementation changes after objects have been created, which is possible in JavaScript, the behaviour of all objects sharing the function will change accordingly.

    Let’s examine all possible ways of creating objects in detail.

    Using a simple function to create plain objects

    In our first example, we created a plain myCar object out of thin air – we can simply wrap the creation code into a function, which gives us a very basic object creator:

    function makeCar() { var newCar = {} newCar.honk = function() { console.log("honk honk"); } }

    For the sake of brevity, the drive function has been omitted.

    We can then use this function to mass-produce cars:

    function makeCar() { var newCar = {} newCar.honk = function() { console.log("honk honk"); } return newCar; } myCar1 = makeCar(); myCar2 = makeCar(); myCar3 = makeCar();

    One downside of this approach is efficiency: for every myCar object that is created, a new honk function is created and attached – creating 1,000 objects means that the JavaScript interpreter has to allocate memory for 1,000 functions, although they all implement the same behaviour. This results in an unnecessarily high memory footprint of the application.

    Secondly, this approach deprives us of some interesting opportunities. These myCar objects don’t share anything – they were built by the same creator function, but are completely independent from each other.

    It’s really like with real cars from a real car factory: They all look the same, but once they leave the assembly line, they are totally independent. If the manufacturer should decide that pushing the horn on already produced cars should result in a different type of honk, all cars would have to be returned to the factory and modified.

    In the virtual universe of JavaScript, we are not bound to such limits. By creating objects in a more sophisticated way, we are able to magically change the behaviour of all created objects at once.

    Using a constructor to create objects

    In JavaScript, the entities that create objects with shared behaviour are functions which are called in a special way. These special functions are called constructors.

    Let’s create a constructor for cars. We are going to call this function Car, with a capital C, which is common practice to indicate that this function is a constructor.

    Because we are going to encounter two new concepts that are both necessary for shared object behaviour to work, we are going to approach the final solution in two steps.

    Step one is to recreate the previous solution (where a common function spilled out independent car objects), but this time using a constructor:

    function Car() { this.honk = function() { console.log("honk honk"); } }

    When this function is called using the new keyword, like so:

    var myCar = new Car();

    it implicitly returns a newly created object with the honk function attached.

    Using this and new makes the explicit creation and return of the new object unnecessary – it is created and returned "behind the scenes" (i.e., the new keyword is what creates the new, "invisible" object, and secretly passes it to the Car function as its this variable).

    You can think of the mechanism at work a bit like in this pseudo-code:

    // Pseudo-code, for illustration only! function Car(this) { this.honk = function() { console.log("honk honk"); } return this; } var newObject = {} var myCar = Car(newObject);

    As said, this is more or less like our previous solution – we don’t have to create every car object manually, but we still cannot modify the honk behaviour only once and have this change reflected in all created cars.

    But we laid the first cornerstone for it. By using a constructor, all objects received a special property that links them to their constructor:

    function Car() { this.honk = function() { console.log("honk honk"); } } var myCar1 = new Car(); var myCar2 = new Car(); console.log(myCar1.constructor); // outputs [Function: Car] console.log(myCar2.constructor); // outputs [Function: Car]

    All created myCars are linked to the Car constructor. This is what actually makes them a class of related objects, and not just a bunch of objects that happen to have similar names and identical functions.

    Now we have finally reached the moment to get back to the mysterious prototype we talked about in the introduction.

    Using prototyping to efficiently share behaviour between objects

    As stated there, while in class-based programming the class is the place to put functions that all objects will share, in prototype-based programming, the place to put these functions is the object which acts as the prototype for our objects at hand.

    But where is the object that is the prototype of our myCar objects – we didn’t create one!

    It has been implicitly created for us, and is assigned to the

    Car.prototype

    property (in case you wondered, JavaScript functions are objects that have properties, too).

    Here is the key to sharing functions between objects: Whenever we call a function on an object, the JavaScript interpreter tries to find that function within the queried object. But if it doesn’t find the function within the object itself, it asks the object for the pointer to it’s prototype, then goes to the prototype, and asks for the function there. If it is found, it is then executed.

    This means that we can create myCar objects without any functions, create the honk function in their prototype, and end up having myCar objects that know how to honk – because everytime the interpreter tries to execute the honk function on one of the myCar objects, it will be redirected to the prototype, and execute the honk function which is defined there.

    Here is how this setup can be achieved:

    function Car() {} Car.prototype.honk = function() { console.log("honk honk"); } var myCar1 = new Car(); var myCar2 = new Car(); myCar1.honk(); // executes Car.prototype.honk() and outputs "honk honk" myCar2.honk(); // executes Car.prototype.honk() and outputs "honk honk"

    Our constructor is now empty, because for our very simple cars, no additional setup is necessary.

    Because both myCars are created through this constructor, their prototype points to Car.prototype – executing myCar1.honk() results in Car.prototype.honk() being executed.

    Let’s see what this enables us to do. In JavaScript, objects can be changed at runtime. This holds true for prototypes, too. Which is why we can change the honk behaviour of all our cars even after they have been created:

    function Car() {} Car.prototype.honk = function() { console.log("honk honk"); } var myCar1 = new Car(); var myCar2 = new Car(); myCar1.honk(); // executes Car.prototype.honk() and outputs "honk honk" myCar2.honk(); // executes Car.prototype.honk() and outputs "honk honk" Car.prototype.honk = function() { console.log("meep meep"); } myCar1.honk(); // executes Car.prototype.honk() and outputs "meep meep" myCar2.honk(); // executes Car.prototype.honk() and outputs "meep meep"

    Of course, we can also add additional functions at runtime:

    function Car() {} Car.prototype.honk = function() { console.log("honk honk"); } var myCar1 = new Car(); var myCar2 = new Car(); Car.prototype.drive = function() { console.log("vrooom..."); } myCar1.drive(); // executes Car.prototype.drive() and outputs "vrooom..." myCar2.drive(); // executes Car.prototype.drive() and outputs "vrooom..."

    But we could even decide to treat only one of our cars differently:

    function Car() {} Car.prototype.honk = function() { console.log("honk honk"); } var myCar1 = new Car(); var myCar2 = new Car(); myCar1.honk(); // executes Car.prototype.honk() and outputs "honk honk" myCar2.honk(); // executes Car.prototype.honk() and outputs "honk honk" myCar2.honk = function() { console.log("meep meep"); } myCar1.honk(); // executes Car.prototype.honk() and outputs "honk honk" myCar2.honk(); // executes myCar2.honk() and outputs "meep meep"

    It’s important to understand what happens behind the scenes in this example. As we have seen, when calling a function on an object, the interpreter follows a certain path to find the actual location of that function.

    While for myCar1, there still is no honk function within that object itself, that no longer holds true for myCar2. When the interpreter calls myCar2.honk, there now is a function within myCar2 itself. Therefore, the interpreter no longer follows the path to the prototype of myCar2, and executes the function within myCar2 instead.

    That’s one of the major differences to class-based programming: while objects are relatively "rigid" e.g. in Java, where the structure of an object cannot be changed at runtime, in JavaScript, the prototype-based approach links objects of a certain class more loosely together, which allows to change the structure of objects at any time.

    Also, note how sharing functions through the constructor’s prototype is way more efficient than creating objects that all carry their own functions, even if they are identical. As previously stated, the engine doesn’t know that these functions are meant to be identical, and it has to allocate memory for every function in every object. This is no longer true when sharing functions through a common prototype – the function in question is placed in memory exactly once, and no matter how many myCar objects you create, they don’t carry the function themselves, they only refer to their constructor, in whose prototype the function is found.

    To give you an idea of what this difference can mean, here is a very simple comparison. The first example creates 1,000,000 objects that all have the function directly attached to them:

    var C = function() { this.f = function(foo) { console.log(foo); } } var a = []; for (var i = 0; i < 1000000; i++) { a.push(new C()); }

    In Google Chrome, this results in a heap snapshot size of 328 MB. Here is the same example, but now the function is shared through the constructor's prototype:

    var C = function() {} C.prototype.f = function(foo) { console.log(foo); } var a = []; for (var i = 0; i < 1000000; i++) { a.push(new C()); }

    This time, the size of the heap snapshot is only 17 MB, i.e., only about 5% of the non-efficient solution.

    Object-orientation, prototyping, and inheritance

    So far, we haven't talked about inheritance in JavaScript, so let's do this now.

    It's useful to share behaviour between a certain class of objects, but there are cases where we would like to share behaviour between different, but similar classes of objects.

    Imagine our virtual world not only had cars, but also bikes. Both drive, but where a car has a horn, a bike has a bell.

    Being able to drive makes both objects vehicles, but not sharing the honk and ring distinguishes them.

    We could illustrate their shared and local behaviour as well as their relationship to each other as follows:

    Vehicle > drive | ---------------------- | | Car Bike > honk > ring

    Designing this relationship in a class-based language like Java is straightforward: We would define a class Vehicle with a method drive, and two classes Car and Bike which both extend the Vehicle class, and implement a honk and a ring class, respectively.

    This would make the car as well as bike objects inherit the drive behaviour through the inheritance of their classes.

    How does this work in JavaScript, where we don't have classes, but prototypes?

    Let's look at an example first, and then dissect it. To keep the code short for now, let's only start with a car that inherits from a vehicle:

    function Vehicle() {} Vehicle.prototype.drive = function () { console.log("vrooom..."); } function Car() {} Car.prototype = new Vehicle(); Car.prototype.honk = function() { console.log("honk honk"); } var myCar = new Car(); myCar.honk() // outputs "honk honk" myCar.drive() // outputs "vrooom..."

    In JavaScript, inheritance runs through a chain of prototypes.

    The prototype of the Car constructor is set to a newly created vehicle object, which establishes the link structure that allows the interpreter to look for methods in parent objects.

    The prototype of the Vehicle constructor has a function drive. Here is what happens when the myCar object is asked to drive():

    • The interpreter looks for a drive method within the myCar object, which does not exist
    • The interpreter then asks the myCar object for its prototype, which is the prototype of its constructor Car
    • When looking at Car.prototype, the interpreter sees a vehicle object which has a function honk attached, but no drive function
    • Thus, the interpreter now asks this vehicle object for its prototype, which is the prototype of its constructor Vehicle
    • When looking at Vehicle.prototype, the interpreter sees an object which has a drive function attached - the interpreter now knows which code implements the myCar.drive() behaviour, and executes it

    A classless society, revisited

    We just learned how to emulate traditional (or classical) inheritance in JavaScript. This understanding is needed to successfully unlearn it and leave it behind, in order to embrace the idea that in JavaScript, you really don't need classes at all, and you therefore don't need to emulate them - plus, that's really a lot of code to express the prototypical idea of "go look at that other object over there, it has the code you are looking for", isn't it?

    It was Douglas Crockford who came up with a very clever solution, which allows to let objects directly inherit from each other, without the need for all the boilerplate code presented in the previous example. The solution is a native part of JavaScript by now - it's the Object.create() function, and it works like this:

    Object.create = function(o) { function F() {} F.prototype = o; return new F(); };

    We learned enough now to understand what's going on. Let's analyze an example:

    var vehicle = {}; vehicle.drive = function () { console.log("vrooom..."); } var car = Object.create(vehicle); car.honk = function() { console.log("honk honk"); } var myCar = Object.create(car); myCar.honk() // outputs "honk honk" myCar.drive() // outputs "vrooom..."

    While being significantly more concise and expressive, this code achieves exactly the same behaviour, without the need to write dedicated constructors and attaching functions to their prototype. As you can see, Object.create() handles both behind the scenes, on the fly. A temporary constructor is created, its prototype is set to the object that serves as the role model for our new object, and a new object is created from this setup.

    Conceptually, this is really the same as in the previous example where we defined that Car.prototype shall be new Vehicle();.

    But wait! We created the functions drive and honk within our objects, not on their prototypes - that's memory-inefficient!

    Well, in this case, it's actually not. Let's see why:

    var vehicle = {}; vehicle.drive = function () { console.log("vrooom..."); } var car = Object.create(vehicle); car.honk = function() { console.log("honk honk"); } var myVehicle = Object.create(vehicle); var myCar1 = Object.create(car); var myCar2 = Object.create(car); myCar1.honk() // outputs "honk honk" myCar2.honk() // outputs "honk honk" myVehicle.drive() // outputs "vrooom..." myCar1.drive() // outputs "vrooom..." myCar2.drive() // outputs "vrooom..."

    We have now created a total of 5 objects, but how often do the honk and drive methods exist in memory? Well, how often have they been defined? Just once - and therefore, this solution is basically as efficient as the one where we built the inheritance manually. Let's look at the numbers:

    c = {}; c.f = function(foo) { console.log(foo); } var a = []; for (var i = 0; i < 1000000; i++) { a.push(Object.create(c)); }

    Turns out, it's not exactly identical - we end up with a heap snapshot size of 40 MB, thus there seems to be some overhead involved. However, in exchange for much better code, this is probably more than worth it.

    ]]>
    /2012/03/23/object-orientation-and-inheritance-in-javascript-a-comprehensive-explanation/feed/ 0
    Project: projectile, an HTML5 canvas game /2012/03/19/project-projectile-an-html5-canvas-game/ /2012/03/19/project-projectile-an-html5-canvas-game/#comments Mon, 19 Mar 2012 00:03:30 +0000 Manuel Kiessling /?p=512 ]]> Some days ago my son asked me how computer games are made. I couldn’t really explain it very well in terms he understood (he’s 5 years old), but I wanted to show it to him. Thus I started working with him on a 2D space shooter written in JavaScript, using the canvas element of HTML5. The result is playable at http://manuel.kiessling.net/projectile/.

    The project source code is hosted at https://github.com/ManuelKiessling/projectile

    ]]>
    /2012/03/19/project-projectile-an-html5-canvas-game/feed/ 0
    Project: bivouac, an HTML5 web chat with filesharing /2012/03/18/project-bivouac-an-html5-web-chat-with-filesharing/ /2012/03/18/project-bivouac-an-html5-web-chat-with-filesharing/#comments Sun, 18 Mar 2012 13:33:36 +0000 Manuel Kiessling /?p=486 Some weeks ago I started working on a new open source software, called bivouac.

    bivouac provides an open source software package which allows to easily setup and run web-based group chats with dead-simple file-sharing (drag a file into the chat, and it’s immediately available as a download for all chat members).

    Besides these “feature goals”, my secondary goal is to learn how to architect JavaScript applications that are relatively complex, with domain-driven design and a strong separation of concerns in mind.

    bivouac is written in JavaScript, for the Node.js platform. It’s hosted at https://github.com/ManuelKiessling/bivouac

    ]]>
    /2012/03/18/project-bivouac-an-html5-web-chat-with-filesharing/feed/ 0
    Deploying Symfony2 Apps via Scalarium: Improved Methodology /2012/01/05/deploying-symfony2-apps-via-scalarium-improved-methodology/ /2012/01/05/deploying-symfony2-apps-via-scalarium-improved-methodology/#comments Thu, 05 Jan 2012 08:04:19 +0000 Manuel Kiessling /?p=453 Some weeks ago I wrote about deploying Symfony2 Applications to Amazon AWS with Scalarium. It turned out that the described methodology can be improved in several ways. Here’s how.

    First, let’s discuss what’s suboptimal with the previously described approach. The basic idea was to provide a custom Chef recipe which is executed on our instances whenever our Symfony2 application gets deployed. This recipe took care of

    • executing the tasks which need to be done whenever the application is deployed, like installing the Symfony2 vendors or cleaning the application cache
    • configuring Apache to correctly serve the application

    Well, the problem is that these are really two very different tasks which shouldn’t be mixed together. Updating the web server configuration every time you release a new version of your application simply doesn’t make sense.

    Thanks to Chef deployment hooks, we can separate these tasks. Whatever needs to be done upon application deployment can be provided within the application itself, making it much more self-contained. This way, application business logic and application deployment logic live in the same source tree.

    On the other hand, system configuration steps which aren’t specific to deploying a new version of your application, but are specific to hosting your application in a given system context, shouldn’t be bundled with your application, but with your system context.

    Thus, we are going to separate the deployment recipes and the system setup recipes. We will provide the deploy recipes from our application, and the system setup recipes through a custom Chef cookbook, just as we did in the first version of this tutorial.

    Let’s look at the old version of our deploy.rb recipe, and decide which parts are related to the deployment of our application, and which parts are related to hosting our application.

    Well, it’s actually quite simple – everything from the beginning of the file through line 44 is stuff that needs to be done upon every single deployment, or else we wouldn’t end up with a working application.

    Let’s move this part of the deployment recipe into our application. Where does it belong? When Scalarium’s Chef deploys our application, it looks for certain scripts in the /deploy directory of our application:

    • /deploy/before_migrate.rb
    • /deploy/before_symlink.rb
    • /deploy/before_restart.rb
    • /deploy/after_restart.rb
    As their names imply, these scripts are triggered at certain points of the deployment lifecycle. They are closely related to the steps that are necessary when deploying Ruby on Rails applications, and thus not all of them are useful for us when deploying a Symfony2 application.

    For the steps we want to execute with our recipe (installing the vendors, clearing the app cache, executing db migrations, installing the assets, and chowning app cache and log dirs), the before_symlink.rb is just fine – it hooks into the deployment process the moment before Chef, after downloading the application source code from Github, changes the symbolic link at /srv/www/symfonyexample/current to the newly downloaded release. At this moment, we have all the source code available, but it is not yet put into production, thus it’s the most sensible moment for additional setup steps.

    Moving the deployment-specific parts of our recipe into this hook gives us a before_symlink.rb script as it’s available in our ScalariumExampleSymfony2Application repository on GitHub.

    The rest of the original recipe is all about configuring Apache in a way that gives us a working vhost for serving our application – this configuration may change, but it isn’t related to any specific deployment. Thus, these steps should be done only when our Scalarium/AWS instance is set up, and not on every deployment.

    And as with the deployment steps, there is a better way to set up Apache for our application, too. Turns out, we don’t need a recipe at all. The reason is that Scalarium implements a very convenient substitution logic – if our own cookbook provides a file with the same name at the same location as one from the Scalarium-provided cookbooks, the file from our own cookbook “wins” and is used instead.

    The Scalarium file we are going to substitute is located at /mod_php5_apache2/templates/default/web_app.conf.erb. By providing this file in our own cookbook repository, it’s used as the template for our Symfony2 application vhost – we don’t even need to define “symfony2::deploy” as a Custom Recipe anymore.

    And that’s it. As described in my previous post on this topic, we need to configure our Scalarium cloud with the information on our custom cookbook and our application, but instead of manually hooking our custom recipe into the configure and deploy events in Scalarium, our newly created deploy hook now lives in the application itself, and is automatically triggered on every deployment, and our newly created web_app.conf.erb Apache vhost template is automatically used by Scalarium’s Chef when setting up new PHP application server instances.

    ]]>
    /2012/01/05/deploying-symfony2-apps-via-scalarium-improved-methodology/feed/ 0
    Cocoa: What to do if outlineView: objectValue ForTableColumn: byItem never gets called /2011/11/15/what-to-do-if-outlineview-objectvaluefortablecolumn-byitem-is-never-called/ /2011/11/15/what-to-do-if-outlineview-objectvaluefortablecolumn-byitem-is-never-called/#comments Tue, 15 Nov 2011 21:10:21 +0000 Manuel Kiessling /?p=441 If you set up an OutlineView in Interface Builder and connect your Controller as its dataSource and delegate (and provide the methods there accordingly), you will notice that

    - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item

    never get’s called. The reason might very simple: in Interface Builder, in the attributes inspector for your OutlineView, you can define the Content Mode as View Based or Cell Based.

    If you simply want to display the content of NSStrings, choose Cell Based, and objectValueForTableColumn will be called.

    Only took me 3 hours to find out.

    ]]>
    /2011/11/15/what-to-do-if-outlineview-objectvaluefortablecolumn-byitem-is-never-called/feed/ 0
    How hosting MyHammer started in a devops way back in the day /2011/11/07/how-hosting-myhammer-started-in-a-devops-way-back-in-the-day/ /2011/11/07/how-hosting-myhammer-started-in-a-devops-way-back-in-the-day/#comments Mon, 07 Nov 2011 15:47:59 +0000 Manuel Kiessling /?p=433 This here is just me, bragging about myself. You have been warned.

    Manuel Kiessling in front of the very first MyHammer FAI server cluster

    This guy with the psychopathic look standing in a room full of rubbish in front of something that vaguely looks like computers is me standing in front of the first MyHammer server cluster, only days before the whole system went into production.

    It was 2005, and I had set up the whole system in a way I’m still quite proud of. Being the only systems administrator at the company at that time, I knew that I wouldn’t face happy times if I would set up the cluster in a traditional way, that is, machine by machine. Although it started small, the system was supposed to grow, especially regarding the web servers, and even I knew that while managing 13 servers individually was doable, it wasn’t fun, and managing several dozen machines just sounded like total nightmare.

    Which is why I thought about better ways to setup and manage the whole cluster. I ended up with a central installation server running FAI – Fully Automatic Installation, and hosting a cfengine server. This way, new machines could be automatically provisioned with the operating system (Debian GNU/Linux) they needed by simply booting from their network adaptor, and new as well as existing systems could easily be maintained, configured, and updated via cfengine. No need to ever log in on a specific machine to change configuration or install software. A centralized syslog server completed the picture.

    cfengine was a major pain in the ass at times, and with Chef and Puppet there a way more sophisticated tools available today, but the overall system ran extremely well and could easily scale over time.

    Years later, the term Devops was coined, and I couldn’t help congratulating myself for getting it right so long ago.

    ]]>
    /2011/11/07/how-hosting-myhammer-started-in-a-devops-way-back-in-the-day/feed/ 0
    Deploying Symfony2 Applications to Amazon AWS with Scalarium /2011/11/01/deploying-symfony2-applications-to-amazon-aws-with-scalarium/ /2011/11/01/deploying-symfony2-applications-to-amazon-aws-with-scalarium/#comments Tue, 01 Nov 2011 10:18:46 +0000 Manuel Kiessling /?p=391 Important Note

    The methodology explained here is outdated, please read Deploying Symfony2 Apps via Scalarium: Improved Methodology for an updated version.

    About

    This article describes how to use the cloud-based cluster-management platform Scalarium in order to automatically mass-deploy Symfony2 applications with a MySQL database backend onto clusters of Amazon EC2 virtual machines by creating a special Symfony2 environment, using a custom Chef recipe, and making use of Doctrine migrations.

    Target audience

    Current or soon-to-be Scalarium customers, devops interested in deploying Symfony2 applications using centralized configuration management tools like Chef or Puppet, PHP developers.

    Prerequisites

    In order to get your Symfony2 application running on Amazon AWS, you need an AWS account, a Scalarium account (correctly set up with your AWS credentials), and a Github account to host your Symfony2 application and your custom Chef recipes. This tutorial assumes that you are already familiar with managing EC2 clusters with Scalarium. It’s tested to work with Symfony 2.0.4 on Ubuntu 11.04 instances.

    Overview

    The above diagram is here to illustrate how the different parts are working together in order to deploy a running application. The virtual machines hosting our Symfony2 application and the database are EC2 instances running in the Amazon AWS cloud. We will use Scalarium to define the layout of our cluster (called a “cloud” in Scalarium), to configure the application which will be deployed onto the application servers within this cluster, and to configure the custom Chef recipes which need to be applied to our application server instances in order to finalize the deployment and setup of our application.

    Looking at the diagram, we could say that Scalarium manages, Amazon runs, and Github provides – Scalarium uses what Github provides in order to run the application on Amazon.

    Because Scalarium already provides the setup logic and recipes that allow us to set up basic Apache/PHP application servers and MySQL database servers on AWS, we will only need to provide what is needed in order to finalize the deployment and setup of our specific Symfony2 application – setting up a basic Ubuntu server, installing software packages like PHP, Apache, MySQL, and checking out our Symfony2 application code from Github is all done by Scalarium without the need to provide additional means.

    The example application

    It makes sense to follow this tutorial using your own Symfony2 application. However, an example application hosted at Github.com → MyHammer → ScalariumExampleSymfony2Application is used to illustrate the process – you are free to use this repository to deploy the application to your Scalarium cloud. The commit history of this repository also shows step by step which changes need to be applied to a Symfony2 application to prepare it for running on a Scalarium cloud.

    Setting up a Scalarium cloud for our application

    Our very first step is to set up a new cloud in Scalarium which manages the EC2 instances, server roles, application configuration and custom Chef cookbooks needed to deploy and run our Symfony2 application.

    In order to do so, click on Add Cloud in the upper right corner of the main Scalarium administration interface. Choose whatever name you like (I will stick with “Symfony”), define a region that makes sense for you (Europe in my case), and choose “Ubuntu 11.04″ as the default operating system. Please choose “Role Dependent” as the Hostname Theme, because this will make it much easier to follow my explanations whenever I’m talking about specific machine instances.

    Assuming that you have already set up Amazon AWS in your Scalarium account, please choose the AWS credentials and SSH keys accordingly.

    You now have an empty cloud. Let’s define these three things in order to host our application:

    • An application
    • Custom Cookbooks
    • An application server and a database server role

    Let’s start with our application. Later, we are going to make some modifications to our application that are necessary for hosting it with Scalarium, but we can already configure it into our cloud. Clicking on Add Application gives us a dialogue in which we can configure where EC2 instances will be able to pull our application from upon bootup or application deployment.

    I’m going to choose “SymfonyExample” as the name. Please choose “PHP” as the Application Type. If you are going to use the sample application that resides on Github, please choose a Repository Type of “Git”, and enter the following Repository URL: “git://github.com/MyHammer/ScalariumExampleSymfony2Application.git”. All other parameters are not important for now – however, if you are configuring your own private repository, you will need to provide a deploy SSH key.

    Although this is sufficient to deploy the code from Github onto our instances, it’s not enough to actually get a running application. Additional steps are necessary after the code has been pulled from Github, and those steps need to be performed using a custom Chef recipe. We are going to write this recipe later, but we can already configure the cookbook that contains the recipe into our cloud. On the cloud overview page, select Manage Cookbooks from the Actions dropdown.

    In the new dialogue, check Enable custom cookbooks, and configure as follows:

    • Repository Type: “Git”
    • Repository URL: “git://github.com/MyHammer/ScalariumExampleSymfony2ChefRecipes.git”
    Deploy SSH Key and Branch / Revision don’t need to be filled out.

    As a last step, our cloud needs two machine roles: one for our application servers, and one for our database server. We will start with the application server role. On the cloud overview page, select Add role, and choose the PHP Application Server role.

    Once you have added it, an additional configuration is necessary: In Custom Recipes, please add the recipe “symfony2::deploy” for the Scalarium actions configure and deploy. This makes sure that our recipe is run everytime our application is deployed to an instance, or whenever the cloud changes.

    Last but not least, create an additional role MySQL Master. Additional configuration is not needed here. If you like, you can already add and boot an instance for this role.

    Modifying the Symfony2 application

    Our Symfony2 application doesn’t need to be re-programmed in any way in order to run via Scalarium – however, its configuration needs to be specifically modified. You can either modify your existing “prod” environment configuration, or you may want to create a new environment called “scalarium”, which is what I did for the example application.

    The nice thing about Scalarium and Symfony2 is that the former provides a very nice PHP interface to the layout of the current cluster, and the latter provides an easy way to make use of this interface.

    This allows us to dynamically configure our application’s database setup, avoiding the need to hard code e.g. the IP address of our MySQL master into the application. Here is a step by step description on how to achieve this:

    First, create a new and empty file /app/config/config_scalarium.yml. This is going to be the main configuration file for the new “scalarium” environment. Fill the file with the following content: imports: - { resource: parameters_scalarium.php } - { resource: config.yml } This makes our new environment use 99% of it’s settings based on those from the “prod” environment – however, an additional file is imported, /app/config/parameters_scalarium.php – this is where we are going to dynamically define our database settings using the power of Scalarium.

    Let’s fill /app/config/parameters_scalarium.php with life: <?php include_once(__DIR__ . '/../../scalarium.php'); $scalarium = new Scalarium(); $container->setParameter('database_driver', 'pdo_mysql'); $container->setParameter('database_host', $scalarium->db->host); $container->setParameter('database_port', '3306'); $container->setParameter('database_name', $scalarium->db->database); $container->setParameter('database_user', $scalarium->db->username); $container->setParameter('database_password', $scalarium->db->password); $container->setParameter('database_path', null); unset($scalarium); What happens here is that the database parameter placeholders like %database_host%, which are used in /app/config/config.yml to configure the database for our application, are programmatically defined based on the current state of the Scalarium cloud. Leveraging the power of the scalarium.php script, which is available in the root directory of our application per default (a symlink is created whenever our application is deployed on an instance), this makes our database config dynamic and therefore always up to date.

    The creators of Scalarium point out that using scalarium.php is just a convenience. The full-stack alternative would be to write a Chef recipe that generates the configuration file and register this recipe on the configure and deploy events. Inside the Chef recipe Scalarium provides you with all necessary information like which hosts exist in the cloud and what their configuration is (e.g. IP addresses, roles, etc.). See http://support.scalarium.com/kb/custom-instance-setup for further information on how to use the Scalarium cloud structure information in your own recipes.

    One important thing to consider here is that the settings in /app/config/parameters.ini overwrite settings with the same name in /app/config/parameters_scalarium.php – we therefore need to remove all lines containing “%database” from parameters.ini!

    The last step is to create a Frontend Controller for our new “scalarium” environment at /web/app_scalarium.php: <?php require_once __DIR__.'/../app/bootstrap.php.cache'; require_once __DIR__.'/../app/AppKernel.php'; //require_once __DIR__.'/../app/AppCache.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('scalarium', false); $kernel->loadClassCache(); //$kernel = new AppCache($kernel); $kernel->handle(Request::createFromGlobals())->send();

    You can look at a visual before-and-after comparison of all these changes on Github:

    Putting the parts together

    Our cloud now has everything in place it needs. Its roles are defined, our application servers know where to pull our application from, instances of role “PHP Application Server” are configured to use our custom Symfony2 deploy recipe, and our application has been modified to make use of the dynamic cloud configuration in a new environment called “scalarium”.

    Let’s take a moment to look at our custom Chef recipe.

    What this recipe does is it checks for each application that is going to be deployed if it’s actually a Symfony2 application, and if yes, it starts by updating the vendors (or installing them from scratch if none exist yet), clears the application’s cache, applies database migrations (if any), makes sure that cache and log files and directories are read and writable for those users that need it, installs and configures an Apache vhost file for the app, and disables the default vhost.

    Ok, let’s deploy our application! All you need to do is to add an instance of role PHP Application Server and boot it up. Everything else happens automatically:

    • Scalarium requests an EC2 instance from Amazon AWS which is booted with a fresh Ubuntu 11.04 image
    • Scalarium sets this machine up with some basic packages like PHP, Apache etc., and executes its basic setup routines (which are Chef recipes, too)
    • Our Symfony2 application is pulled from Github and deployed to /srv/www/symfonyexample/current
    • The instance executes our custom Chef recipe symfony2::deploy which installs the vendors, clears the app cache, applies the database migrations, installs the web assets, sets users and permissions on cache and log files, and configures an Apache vhost for our application

    Once this is done, you can browse to the public IP of the booted application server instance, which will display the Symfony2 welcome page.

    ]]>
    /2011/11/01/deploying-symfony2-applications-to-amazon-aws-with-scalarium/feed/ 0
    Behaviour-driven node.js development with stubbing by combining Vows and node-gently /2011/04/13/behaviour-driven-node-js-development-with-stubbing-by-combining-vows-and-node-gently/ /2011/04/13/behaviour-driven-node-js-development-with-stubbing-by-combining-vows-and-node-gently/#comments Wed, 13 Apr 2011 18:35:16 +0000 Manuel Kiessling /?p=374 I’m about 3.5 hours into node.js development, I guess that qualifies me to give advice on it on this Internet thing.

    Being the BDD fanatic that I am, I wanted to start off behaviour-driven right from the beginning, and Vows looked like a good choice.

    However, I quickly came to the point where I needed to stub out a dependency in one of my modules, and as far as I can see, Vows doesn’t provide mocking/stubbing. But https://github.com/felixge/node-gently does, and here is my approach at combining these two:

    This is the Vows spec: var gently = global.GENTLY = new (require("gently")); var vows = require("vows"), assert = require("assert"); var myModule = require("MyModule"); vows.describe("My Module").addBatch({ "when calling its foo() method": { topic: myModule, "it triggers a console message": function (topic) { gently.expect(gently.hijacked.sys, "puts", function(str) { assert.equal(str, "Hello World"); }); topic.foo("Hello World"); } } }).export(module);

    And this is the implementation of MyModule: if (global.GENTLY) require = GENTLY.hijack(require); var sys = require("sys"); function foo(message) { sys.puts(message); return true; } exports.foo = foo;

    No idea if this makes any sense in the long run – I will tell you when I’m about 14 hours or so into BDD node.js development…

    ]]>
    /2011/04/13/behaviour-driven-node-js-development-with-stubbing-by-combining-vows-and-node-gently/feed/ 0
    The only job application form that makes sense /2011/04/11/the-only-job-application-form-that-makes-sense/ /2011/04/11/the-only-job-application-form-that-makes-sense/#comments Mon, 11 Apr 2011 10:00:14 +0000 Manuel Kiessling /?p=370 It just dawned on me that this is really the only job application form that makes sense, isn’t it?

    Job Application Form

    ]]>
    /2011/04/11/the-only-job-application-form-that-makes-sense/feed/ 0
    Why developing without tests is like driving a car without brakes /2011/04/07/why-developing-without-tests-is-like-driving-a-car-without-brakes-2/ /2011/04/07/why-developing-without-tests-is-like-driving-a-car-without-brakes-2/#comments Thu, 07 Apr 2011 07:37:55 +0000 Manuel Kiessling /?p=367

    The following roots in something I heard from Jon Jagger at QCon London 2011 after his fantastic talk about Deliberate Practice. It was related to Test Driven Development. He asked “Why do cars have brakes?”. It made us think “To stop!”, but he said “No – to go faster”.

    (Jon points out he didn’t invent it, he heard it from Kevlin Henney).

    I have been thinking about this ever since, and here is what I came up with.

    Imagine I would give you the keys to my car. I would tell you “here are the keys, you can drive wherever you want, including the highway, have fun!”

    How fast would go? My car is not exactly a sports car, but it can do around 200 km/h. I guess we both agree that you would drive around 50 km/h within cities (the maximum allowed in Germany), and probably up to 200 km/h on the highway, as long as there is no limit.

    Fine. Now image this: I would give you the keys to my car. I would tell you “here are the keys, you can drive wherever you want, including the highway, have fun! Oh, just one thing, the brakes don’t work.”

    Now let’s forget for a moment that in reality, you probably wouldn’t start at all, if you had to drive, then how fast would you go? 10 km/h, maybe 20? Driving extremely cautious, always trying to look as far ahead as possible if you are going to need to halt? Yeah, I thought so.

    But why is that? The brakes don’t have anything to do with the speed of my car – it’s still capable of doing 200 km/h just fine!

    It’s because the ability to stop is what enables you to go real fast. With only a bit of exaggaration you could say that having a brake allows for a very “iterative” way of driving – no cars within the next 300 meters, let’s accelerate a bit – oh, there’s a car coming over from the right, let’s brake a bit – ok, now I can accelerate again – ah, there is a signal that suddenly turned red, no problem, I will stop here.

    For me, this metaphor is the best I could find by now to explain to myself (and in the future, to others), why I really want to develop test-driven, and why it actually makes me faster, not slower, although I’m doing more.

    Just as the brake doesn’t directly influence your driving speed, but does so indirectly, your tests won’t influence your coding speed directly, but indirectly. It’s because once they are in place, they allow you to iterate over your code and refactor it at what I, from my own experience, can only describe as the speed of light compared to conventional programming.

    With tests in place, it’s like: Mh, what if I would split this rather long method into two? – ok, works; What if I put a bit more of dependency injection into this class? – ah, now this test here fails, no problem, I will have it back to green within minutes, I know exactly where to go to fix this; Hey, I could give this method here a better name – ok, still green; There’s this performance bottleneck deep inside this one class that is heavily used by a lot of other classes, let’s see if I can fix this – my tests will tell me if I accidently changed behaviour.

    Compare this to conventional programming: You will never know for sure what breaks somewhere else if you change something. If you want to find out, you need huge amounts of manpower to have your webpage or UI tested for regression. What really happens is that you slow down to a near halt: because you don’t know what’s around the next corner when developing, and you know there is nothing that will immediately stop you and save you from harm if you take that next corner, you will drive, err, code so cautious, you won’t make any real progress.

    On which Jon commented: “Yes. As the pragmatic programmers say, paraphrasing – you don’t know why it’s broken because you didn’t know why it worked in the first place.
    ]]>
    /2011/04/07/why-developing-without-tests-is-like-driving-a-car-without-brakes-2/feed/ 0
    Visualization: Why working iterative works /2011/03/10/visualization-why-working-iterative-works/ /2011/03/10/visualization-why-working-iterative-works/#comments Thu, 10 Mar 2011 16:48:18 +0000 Manuel Kiessling /?p=299 I’m really into visualizations. More often then not I can only really “get” something (a complex system, an abstract idea, a process etc.) when I see it visualized. You could call this the transformation of gut feelings into images.

    So, I had this (rather obvious) gut feeling that working iterative in software projects makes a lot of sense, I’ve heard all the arguments and explanations and examples and stuff like that, and I probably already “got it”, but I thought it could make sense to clearly work out why exactly it makes sense, by visualizing it. Surely it’s no rocket surgery what happens here, but I kind of like it and would like to share it.

    So here’s my approach:



    The customer tells a product manager what he wants him to build. Let’s see how a waterfall approach leads to the product team failing at this:


    The reason why what is finally delivered isn’t what the customer expected is that the project goes through the hands of different people and different stages, and every time the project is given to another person or team, the amount of misunderstanding grows. That’s only natural because we cannot copy ideas from one brain to another in a 1:1 manner.

    Here is why an iterative approach makes sense:


    The project really starts the same: There is a certain amount of misunderstanding, and the team does things wrong. But due to the regular feedback from the customer, this wrong direction can be corrected. It might then move into another direction which is still a bit wrong, but then comes the next correction, and finally everything is on track.

    ]]>
    /2011/03/10/visualization-why-working-iterative-works/feed/ 0
    Interview mit mir auf dem O’Reilly Blog /2011/01/31/interview-mit-mir-auf-dem-oreilly-blog/ /2011/01/31/interview-mit-mir-auf-dem-oreilly-blog/#comments Mon, 31 Jan 2011 12:26:43 +0000 Manuel Kiessling /?p=289 Das Blog von O'Reilly Deutschland hat in seiner Reihe "Karriere(n) in der IT" ein kurzes Interview mit mir geführt.

    ]]>
    Das Blog von O’Reilly Deutschland hat in seiner Reihe “Karriere(n) in der IT” ein kurzes Interview mit mir geführt:

    http://community.oreilly.de/blog/2011/01/31/job-portrait-softwarenentwickler-bei-myhammer-de/

    ]]>
    /2011/01/31/interview-mit-mir-auf-dem-oreilly-blog/feed/ 0
    Empfehlung: Literatur für Manager /2011/01/21/literatur-fuer-manager/ /2011/01/21/literatur-fuer-manager/#comments Fri, 21 Jan 2011 13:52:04 +0000 Manuel Kiessling /?p=272 Ich werde oft gefragt, wie ich so ein hervorragender Manager geworden bin. Haha, quatsch, kein Mensch fragt mich das. Ich stelle mir nur manchmal vor, dass es so wäre. Dann weine ich mich langsam in den Schlaf… Wo war ich? Ach ja.

    Also, ich wurde nach Literatur zum Thema Management bzw. Mitarbeiterführung gefragt. Spontan fiel mir dazu erst mal nicht viel ein, weil ich keinen Kanon dazu im Hinterkopf habe, und weil Führungsqualitäten sowieso nur bedingt anlesbar sind. Dann sind mir aber doch ein paar Quellen eingefallen die mir vieles klarer gemacht haben und auf deren Erkenntnisse ich in der Praxis immer wieder zurückgreifen konnte:

    Samy Molcho – Alles über Körpersprache

    Kein Buch über Management im engeren Sinne. Ist aber eine gute Anleitung für den Umgang mit Menschen, also das, was man in 99,9% der Zeit als Manager tun muss. Hat mir übrigens vor allem geholfen, mich selbst einzuschätzen, der Aspekt “ich lese jetzt die Körpersprache anderer Menschen und kann praktisch ihre Gedanken lesen” ist denke ich überbewertet. Übrigens das vielleicht wichtigste Buch als Vorbereitung auf ein Bewerbungsgespräch.

    Link zu Amazon: Alles über Körpersprache: sich selbst und andere besser verstehen

    Project Management lessons from NASA

    http://www.mariosalexandrou.com/blog/project-management-lessons-from-nasa/

    Jeder einzelne Satz ist Gold wert und sollte in Bezug auf die eigene Situation reflektiert werden. Das ist schon eine Zusammenfassung, müsste ich es noch weiter runterdestillieren, wären das meine wichtigsten Punkte:

    • Most managers succeed on the strength and skill of their staff.
    • Sometimes the best thing to do is nothing. It is also occasionally the best help you can give. Just listening is all that is needed on many occasions. You may be the boss but, if you constantly have to solve someone’s problems, you are working for him.
    • Never assume someone knows something or has done something unless you have asked them.
    • Never ask management to make a decision that you can make. Assume you have the authority to make decisions unless you know there is a document that states unequivocally that you cannot.

    Dale Carnegie – Wie man Freunde gewinnt: Die Kunst, beliebt und einflussreich zu werden

    In Teilen etwas angestaubtes, aber sehr lehrreiches Buch, das vor allem sehr menschlich und berührend vermittelt, wie man andere Menschen behandeln sollte. Ich konnte für meine Arbeit als Manager unglaublich viel davon ableiten.

    Link zu Amazon: Wie man Freunde gewinnt: Die Kunst, beliebt und einflussreich zu werden

    Michael Lopp – Managing Nerds

    Zu guter Letzt noch ein lesenswerter Aufsatz für alle, die nicht nur irgendwen, sondern ein Team von Nerds managen dürfen: http://www.randsinrepose.com/archives/2011/01/17/managing_nerds.html

    ]]>
    /2011/01/21/literatur-fuer-manager/feed/ 0
    Neues Projekt: Platform Health Viewer /2011/01/11/neues-projekt-platform-health-viewer/ /2011/01/11/neues-projekt-platform-health-viewer/#comments Tue, 11 Jan 2011 08:16:53 +0000 Manuel Kiessling /?p=247 Platform Health Viewer (kurz PHV) ist mein aktuelles Ruby on Rails Hobbyprojekt.

    Sobald es einen stabilen Zustand erreicht, wird dieses Tool das Sammeln und Visualisieren verschiedener statistischer Daten, wie sie typischerweise von Internetplattformen erzeugt werden, schnell und leichtgewichtig ermöglichen. Beispiele für diese Daten sind Dinge wie die CPU Last einzelner Systeme, Benutzerlogins, Anzahl der Seitenaufrufe usw.

    Die Applikation basiert in erster Linie auf Rails, der HTTP Server für die Datenanlieferung ist in node.js geschrieben, die Weboberfläche nutzt sehr ausgiebig jQuery und für die Erzeugung von SVG Graphen die Raphaël Bibliothek. Massendaten werden in SQL gespeichert, weitere Daten liegen in einer CouchDB.

    Der Projektcode ist auf Github abrufbar unter https://github.com/ManuelKiessling/PlatformHealthViewer.

    Das folgende Video ist eine kurze Einführung zur aktuellen Alphaversion des Projekts. Es enthält außerdem eine lustige Sprecherstimme und eine sehr kreative Interpretation der englischen Grammatik.


    Im Folgenden das ins Deutsche übersetzte Transskript des Videos:

    Hi. Platform Health Viewer – oder PHV – ist mein aktuellen Hobbyprojekt.

    Ich brauche eine einfache und leichtgewichtige Möglichkeit, die verschiedenen Kennzahlen der Webseite, für die ich verantwortlich bin, zu sammeln und zu visualisieren. Sachen wie die CPU Perfomance wichtiger Systeme, Userlogins, HTTP Anfragen.

    Deshalb habe ich angefangen mit Ruby on Rails, jQuery, CouchDB und node.js zu experimentieren, und hier ist eine frühe Alphaversion, die ich demonstrieren möchte.

    Mein Hauptziel ist es, den Prozess von der Einspeisung der Daten in das System bis hin zu ihrer grafischen Visualisierung so einfach wie möglich zu gestalten.

    Um Daten in das System zu bekommen, benötigt man lediglich einen HTTP Aufruf, was es sehr einfach macht, die Daten der unterschiedlichsten Quellen zu sammeln.

    Probieren wir ein Beispiel aus. I möchte die CPU Performance meiner lokalen Maschine visualisieren.

    Ich werde diese Daten bekommen, indem ich einen Standard Unix Befehl verwende: sar.

    Dies ist ein wichtiger Aspekt meines Ansatzes: Für den Platform Health Viewer spielt es überhaupt keine Rolle, woher die Daten stammen – man ist bei den Mitteln der Datenbeschafung völlig frei. Dadurch kann man wirklich alles in das System übermitteln, angefangen bei allgemeinen Daten wie der CPU Last bis hin zu äußerst individuellen Sachen wir den Logins auf der eigenen Webseite.

    Ok, so bekomme ich den CPU “usr” Wert auf meiner OS X Kommandozeile:

    sar 1 1| grep Average| cut -b 14-15

    Fein, das wird’s tun.

    Wie liefern wir diese Werte in das System? Es reicht ein simpler HTTP Post Aufruf mithilfe von curl:

    curl –data “event[value]=`sar 1 1| grep Average| cut -b 14-15`&event[source]=macbook&event[name]=cpu_usr_percentage” http://localhost:3000/queue_event

    Wie man sieht, die Nutzdaten des Aufrufs bestehen aus lediglich drei Parametern: Der Quelle des Events, dem Namen des Events, und seinem Wert.

    Noch mal: Man ist an dieser Stelle komplett flexibel, man ist nicht gezwungen Eventnamen und -quellen zuvor im PHV zu konfigurieren – man definiert diese einfach im Moment der Dateneinlieferung, das das System akzeptiert diese. Wir werden gleich sehen, wie man mit den verschiedenen Events, die in das System geschrieben werden, sinnvoll umgeht.

    Ok, ich verwende jetzt ein kleines Hilfsskript das ich geschrieben habe, um die CPU sys, idle, usr und nice Werte in das System zu liefern:

    cat script/agents/macosx/cpu_overview_percent.sh

    Wie man sieht, geschieht alles unter der Verwendung normaler Unixbefehle.

    Starten wir also das Skript:

    bash ./script/agents/macosx/cpu_overview_percent.sh http://localhost:3000/ macbook

    Ich übergebe hier nur zwei Parameter, die URL zum Platform Health Viewer (der für diese Demonstration auf demselben Host läuft), und den Namen meiner Eventquelle, die ich “macbook” nenne. Eventnamen und -werten kommen direkt aus dem Hilfsskript.

    Man sieht, wie das Skript alle vier CPU Kennzahlen in das System liefert. Schauen wir uns diese Daten innerhalb des Platform Health Viewer an.

    Nun, das Dashboard ist nach wie vor leer, da wir noch keinerlei Visualisierungen definiert haben. Aber der “Tageditor” zeigt ebenfalls noch keinerlei Events an. Das liegt daran, dass die in das System eingelieferten Events noch nicht zu sogenannten Eventtypen normalisiert wurden.

    Dies ist bewusst ein zusätzlicher Schrit, denn es erlaubt dem System, eingehende Events so schnell wie möglich in die Datenbank speichern zu können, ohne sie in Hinblick auf Name und Quelle normalisieren zu müssen. Diese Normalisierung erledigt ein Rake Task:

    rake queue:convert

    Dieser Task liest die Events aus der Anlieferungs-Queue, erzeugt bei Bedarf neue Eventtypen, oder verbindet die Events mit bereits existierenden Eventtypen, falls diese bereits existieren. Abschliessend wird die Anlieferungsqueue geleert.

    Zurück im Tageditor, können wir die vier Eventtypen nun sehen.

    Ein Eventtyp ist die Kombination einer Eventquelle und eines Eventnamen, also ist “macbook – cpu_idle_percentage” ein Eventtyp.

    Schauen wir nun, wie wir den Tageditor verwenden können um etwas sinnvolles zu basteln. Das Gruppieren von einem oder mehreren Eventtypen unter einem Tag macht unsere eingelieferten Daten visualisierbar. Ich bin übrigens nicht ganz glücklich mit dem Begriff “Tag”, vielleicht fällt mir da noch etwas besseres ein.

    Wie auch immer, erzeugen wir nun einen einfachen Tag den wir benutzen können, um genau einen Wert zu visualisieren.

    Ich werde diesen Tag “macbook_cpu_usr” nennen. In diesen laufen dann alle Events, deren Quelle “macbook” und deren Name “cpu_usr_percentage” lautet. Ich könnte diese Parameter auch in die Textbox eintippen, aber es ist einfacher sie schlicht per Drag&Drop in das Formular zu ziehen.

    Ok, fügen wir diesen Tag also hinzu.

    Wir haben nun also einen ersten Tag, und um zu sehen, ob er wie erwartet funktioniert, kann ich die Werte der zugeordneten Events in einer Vorschau kontrollieren.

    Liefern wir jetzt ein paar weitere Werte in das System und schauen, ob sie dann hier angezeigt werden.

    Ok, ich starte also mein Hilfsskript erneut um neue Werte in den Server zu liefern, und starte dann wiederum den Rake Task um die Werte zu normalisieren.

    Ein erneuter Klick auf “Show latest events” zeigt diese neuen Werte nun an.

    Ich starte die Datenanlieferung jetzt in einer Schleife, um viele Werte zu erhalten.

    Ok, wir haben nach wie vor keine Datenvisualisierung, also gehen wir das jetzt an. Ich wechsle in’s Dashboard und füge einen Frame hinzu, dies ist ein Container der unsere Graphen enthalten wird.

    Ein Frame ist die Visualisierung aller Werte die mit einem Tag verbunden sind, also muss ich den Namen des Tags angeben, das ich mit diesem Frame visualisieren möchte.

    “Add frame”, und los geht’s. Ein einfacher Liniengraph, der einen meiner CPU Werte repräsentiert. Der Graph ist im Übrigen ein SVG, erzeugt mit Raphael, einer fantastischen JavaScript Bibliothek.

    Und dank jQuery kann ich diesen Graphen frei bewegen und skalieren.

    Erzeugen wir nun einen Graphen für alle meine CPU Werte. Zurück im Tageditor ziehe ich nun alle meine Eventtypen zusammen.

    Ich kann übrigens Tags erzeugen, indem ich Eventquellen und -namen mit bereits existierenden Tags kombiniere, wie man hier sieht.

    Ich überprüfe alle Werte die meinem neuen Tag zugeordnet sind, und dort sieht man alle CPU Werte, die mein Skript gesammelt hat.

    Wieder zurück im Dashboard gehe ich her und erzeuge einen weiteren Frame, für meinen neuen Tag. Wie man sieht, enthält dieser Frame vier Liniengraphen und zeigt mir so eine hübsche Übersicht meiner kompletten CPU Performance. Natürlich wird hier eine Legende benötigt, etwas das bisher noch nicht implementiert ist.

    Nun, das ist es, das ist der aktuelle Stand des Projekts. Ich würde mich sehr über Feedback freuen, der Code kann auf Github geforkt werden oder schreibt mir eine Mail.

    Danke für’s Interesse.

    ]]>
    /2011/01/11/neues-projekt-platform-health-viewer/feed/ 0
    New project: Platform Health Viewer /2011/01/11/platform-health-viewer/ /2011/01/11/platform-health-viewer/#comments Tue, 11 Jan 2011 07:39:48 +0000 Manuel Kiessling /?p=233 Platform Health Viewer is my current Ruby on Rails pet project.

    Once stable, it will allow users to easily collect and visualize different types of statistical data which is typically produced by internet platforms, like CPU performance, user logins, HTTP requests etc.

    The main application is build on Rails, the server used for data collection is written in node.js, the web interface makes heavy use of jQuery and uses Raphaël to create SVG graphs. Mass data is saved in a SQL db, other data is stored using CouchDB.

    The project’s code is hosted on Github at https://github.com/ManuelKiessling/PlatformHealthViewer.

    This video is a short introduction to the current alpha version of the project. A funny voice and lots of grammatical shortcomings are included for free:


    Transcription of the video:

    Hi. Platform Health Viewer – or PHV – is my current pet project.

    I need an easy and lightweight way to collect and visualize the different key performance indicators of the web platform I’m responsible for – stuff like CPU performance of important systems, user logins, http requests.

    So I started to play around with Ruby on Rails, jQuery, CouchDB and node.js, and here is an early alpha I would like to demonstrate.

    My primary goal was to make the process from feeding data into the system to visualizing that data as simple as possible.

    In order to get data into the system, all you need to make is an HTTP call, which makes it very easy to collect data from very different sources.

    Let’s try an example. I would like to visualize the cpu usage of my local machine.

    I’m going to collect this data using a standard unix command, sar.

    That’s an important aspect of my approach: It doesn’t play any role for the Platform Health Viewer where the data comes from, you’re completely free to choose how to collect it. This way you can feed really anything into the system, from generic data like CPU load to highly individual stuff like the user logins of your specific web site.

    Ok, here is how I can get my cpu “usr” value on my OS X command line:

    sar 1 1| grep Average| cut -b 14-15

    Great, that will do.

    How do we push these values into the system? It’s a simple http post request using curl:

    curl –data “event[value]=`sar 1 1| grep Average| cut -b 14-15`&event[source]=macbook&event[name]=cpu_usr_percentage” http://localhost:3000/queue_event

    As you can see, the payload of the post requests is just 3 parameters: the source of the event, the name of the event, and its value.

    Again, you’re completely free here, you don’t need to configure event names and sources inside PHV – just define them when pushing data into the system, it will happily accept it. We will see in a moment how to make sense of different events that were pushed into the system.

    Ok, let’s use a small helper script I wrote in order to feed the CPU sys, idle, usr and nice values into my system:

    cat script/agents/macosx/cpu_overview_percent.sh

    As you can see, this is all done using only standard unix commands.

    Let’s start the script:

    bash ./script/agents/macosx/cpu_overview_percent.sh http://localhost:3000/ macbook

    I’m just providing two parameters here, the URL to my platform health viewer installation, which resides on the same host for this demo, and the source name, which I call “macbook”.

    As you can see, my script pushes all four CPU usage values into the system. Now let’s have a look at this data within platform health viewer.

    Well, the Dashboard is still empty, because we did not yet define any visualizations. But the “Tageditor” doesn’t show any events, too. This is because the events I pushed into the system have not yet been normalized to event-types.

    This is an additional step, because it will allow the system to push incoming events into the database as quickly as possible without the need to normalize those events regarding their name and source. This normalization is done using a rake task:

    rake queue:convert

    This task reads the events from the incoming queue, creates new event-types as needed, or connects the event values with existing event types if they already exists. It then deletes the incoming queue.

    Getting back to our tageditor, we can now see our 4 event types.

    An event type is the combination of an event source and an event name, so “macbook – cpu_idle_percentage” is one event type.

    Let’s see how we can use the tag editor to create something useful. Grouping one or more event types into a tag is what makes our data suitable for visualization. I’m not quite happy with the term “tag” by the way, maybe I will come up with something better.

    Anyway, let’s create a very simple tag which we can use to visualize exactly one value.

    I’m going to name my tag “macbook_cpu_usr”. It will hold all events whose source matches “macbook”, and whose name matches “cpu_usr_percentage”. I could type those parameters into the text box, but it’s easier to just drag’n'drop them there.

    Ok, let’s add this tag.

    Now we have this first tag, and to check if it works as expected, I can preview the values of the matching events.

    Let’s push some new values into our system and check if they are visible here.

    Ok, I’m starting my helper skript again in order to post new values to the server, and I start my rake task in order to normalize these values.

    Clicking again on “Show latest events” now shows these values.

    I will now start data push and normalization in a loop in order to get a lot of values.

    Ok, we still have no data visualization, so let’s do this now. Let’s switch to the Dashboard and add a frame, which is a container that will hold our graph.

    A frame is the visualization of all values connected to a tag, so I need to provide the name of the tag I want to visualize with this frame.

    “Add frame”, and here we go. A simple line graph representing one of my CPU values. The graph is actually an SVG, created using Raphael, an awesome JavaScript library.

    And thanks to jQuery, I can freely move and resize the graph.

    Let’s create a graph with all my CPU values in it. Back to the Tageditor, I’m going to drag all my values together.

    I can also create tags by combining event-sources and -names with already existing tags, as you can see here.

    Let’s check the values of my new tag, and there are all the different CPU values my script collects.

    Back to the Dashboard, I’m going to create another frame for my new tag. As you can see, this one contains 4 linegraphs and gives me a nice overview of my system’s CPU performance. Of course, a graph legend is needed, something that’s not yet implemented.

    Well, that’s it, that’s the current state of this project, I would love to hear your feedback, you can fork the code on github and drop me an e-mail.

    Thanks for your interest.

    ]]>
    /2011/01/11/platform-health-viewer/feed/ 0
    Testgetriebene Administration – test driven administration /2010/09/01/testgetriebene-administration-test-driven-administration/ /2010/09/01/testgetriebene-administration-test-driven-administration/#comments Wed, 01 Sep 2010 22:57:25 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=188 Ich hatte tatsächlich einmal eine ganz eigene Idee. Und sie war gut, auch nachdem ich sie mehrmals durchgekaut und von allen Seiten beleuchtet hatte.

    Wieso eigentlich sollte man die Prinzipien und Methodiken von testgetriebener Softwareentwicklung nicht auch auf den Bereich der IT-Systemadministration übertragen? Also in aller Kürze: Ich definiere Tests, die das vom noch zu implementierenden System erwartete Verhalten prüfen, sehe zu wie diese Tests fehlschlagen, und erfülle dann schrittweise diese Tests, indem ich das System aufbaue. Test driven administration – TDA.

    Da war ich ganz alleine drauf gekommen, und ich war sehr stolz.

    Dann habe ich gegoogelt. Die Idee existiert seit mindestens 2006.

    Aber hey, gut ist die Idee trotzdem, also beschreibe ich sie hier.

    Warum möchte man testgetrieben administrieren? Die Gründe sind dieselben wie bei testgetriebener Entwicklung: Habe ich Tests, bin ich gegen Regression geschützt, d.h. ändert ein Stück Code / ein System sein Verhalten aufgrund von Änderungen, weisen mich die Tests darauf hin.

    Gehe ich testgetrieben vor, sind die Tests nicht irgendwas, das ich ganz unbedingt machen sollte, das aber doch am Ende runterfällt, sondern sie sind garantiert vorhanden. Mit den bekannten angenehmen Begleiterscheinungen, dass die Tests einen zwingen, sich Gedanken darüber zu machen, wie das Ziel eigentlich beschaffen sein soll, und automatisch dazu führen, die Lösung schlank und elegant umzusetzen.

    Code und IT-Systeme sind aber nicht dasselbe, wie würde man also in der Praxis konkret vorgehen? Hier mein Vorschlag.

    Zuerst benötigt man ein Testwerkzeug. Um in der Softwareentwicklung Unittests zu bauen, benutzt man Tools aus der xUnit Familie wie JUnit oder phpUnit. Das Äquivalent zu diesen Tools in der Systemadministration sind Monitoringsysteme wie Nagios oder Zabbix.

    In der Softwareentwicklung formuliert man Unittest so, dass man eine kleine Einheit des Gesamtsystems, also in der Regel die einzelnen Methoden einer Klasse, mit einer gewissen Erwartungshaltung (“wenn ich diese Parameter reingebe, erwarte ich jenen Rückgabewert”) aufruft, und dann die erwartete Rückgabe mit der tatsächlichen vergleicht.

    Was wäre dementsprechend “erwartetes Verhalten” bei einem IT-System? Nehmen wir an, die Anforderungen lauten wie folgt:

    Benötigt wird ein Linux-System, welches unter der IP 123.456.789.000 einen Webserver bereitstellt, und die Festplattengröße des Systems soll 100 GB betragen.

    In der Realität wären die Anforderungen natürlich umfangreicher, aber ich halte das Beispiel einfach.

    Aus den Anforderungen lässt sich das gewünschte Verhalten ableiten:

    • Bei einem Ping auf 123.456.789.000 muss eine Antwort erfolgen
    • Die Abfrage des Betriebssystems unter dieser IP muss “Linux” ergeben
    • Ein HTTP Request gegen diese IP unter Port 80 muss eine HTTP Antwort zur Folge haben
    • Bei der Abfrage der Festplattengröße muss ein Wert von 100 GB zurückgeliefert werden

    Daraus wiederum kann man im Monitoringsystem Tests formulieren. Diese lässt man einmalig laufen, um zu verifizieren, dass sie tatsächlich fehlschlagen. Und dann beginnt man damit, ein System aufzusetzen, das die Testbedingungen erfüllt, bis schliesslich alle Tests “grün” sind.

    Das ist der Kern der Idee. Im weiteren Verlauf überwacht man die Tests regelmäßig (was man mit einem Monitoringsystem ja eh tut), und hat damit das Thema Continuous Integration gleich mit erschlagen. Ansonsten geht man genauso wie auch beim TDD vor: Möchte man Änderungen an einem System vornehmen, passt man zuerst die Tests an, verifiziert dass sie fehlschlagen, und ändert dann das System, um die Tests wieder zu erfüllen.

    ]]>
    /2010/09/01/testgetriebene-administration-test-driven-administration/feed/ 0
    <angular/> – ein radikal neuer Weg, Ajax Applikationen zu schreiben /2010/08/25/angular-ein-radikal-neuer-weg-ajax-applikationen-zu-schreiben/ /2010/08/25/angular-ein-radikal-neuer-weg-ajax-applikationen-zu-schreiben/#comments Wed, 25 Aug 2010 09:21:13 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=158 <angular/> bringt JavaScript-Logik und das dazugehörige HTML Dokument deutlich näher zueinander als bestehende Frameworks wie beispielsweise jQuery. Es entfernt gleich mehrere Ebenen an Abstraktion, die ein Stück JavaScript-Code und das DOM-Element, auf welchem der Code operieren möchte, voneinander trennen.]]> JavaScript, Ajax und DHTML sind nicht wirklich meine Welt. Zum einen, weil ich einfach grundsätzlich eher mit dem Backend einer Software als mit dem Frontend zu tun habe, zum anderen, weil ich immer schon das ungute Gefühl hatte, in diesem Bereich muss man einfach deutlich zu viel Code produzieren um damit dann gefühlt deutlich zu wenig zu erreichen.

    Umso mehr hat <angular/> mein Interesse geweckt. Die Autoren versprechen:

    Write less code. A lot less. Forget about writing all that extra JavaScript to handle event listeners, DOM updates, formatters, and input validators. comes with autobinding and built-in validators and formatters which take care of these. And you can extend or replace these services at will. With these and other services, you’ll write about 10x less code than writing your app without .

    In einem Video versucht Miško Hevery zu erklären, was <angular/> eigentlich ist, und stellt fest dass diese Erklärung schwierig ist:

    Mein Verständnis ist in erster Linie: <angular/> bringt JavaScript-Logik und das dazugehörige HTML Dokument deutlich näher zueinander als bestehende Frameworks wie beispielsweise jQuery. Es entfernt gleich mehrere Ebenen an Abstraktion, die ein Stück JavaScript-Code und das DOM-Element, auf welchem der Code operieren möchte, voneinander trennen.

    Während man bei traditioneller JavaScript-Programmierung stets gezwungen ist, explizit das HTML Dokument mit JavaScript-Code zu manipulieren, macht <angular/> die Verbindung zwischen Logik und HTML-Repräsentation implizit – etwas, das mich übrigens stark an die Mechanik erinnert, die Max Winde für siqqel einsetzt.

    Spielen wir ein einfaches Beispiel durch, welches ich dank der rein clientseitigen Arbeitsweise von <angular/> problemlos direkt hier im Post zum laufen bringen kann.

    Zuerst binde ich die <angular/> JavaScript Bibliothek ein: <script type="text/javascript" src="http://angularjs.org/ng/js/angular-debug.js" ng:autobind> </script> Nun definiere ich ein Input Feld sowie einen <angular/>-Platzhalter, welche beide in einer Beziehung zueinander stehen: Dein Name: <input type="text" name="deinname" value="Manuel"/> <br /> Hallo {{deinname}}!

    Wodurch entsteht diese Beziehung? Sie ist dank Autobinding implizit, und mappt alleine aufgrund des Formularfeldnamens und des Platzhalternamens beide zusammen.

    Das Ergebnis sieht man hier – einfach den Inhalt des Textfeldes ändern:

    Eingabe: – Hallo {{yourname}}!

    Dieses Beispiel geht natürlich maximal als Spielerei durch. Es zeigt aber schon, wieviel weniger Code nötig ist, als dies mit einem klassischen Framework der Fall wäre.

    Ein etwas praxisnäheres Beispiel findet man unter http://angularjs.org/Cookbook:BasicForm. In diesem Beispiel geht es um den klassischen Fall, Eingaben in ein Textfeld per JavaScript clientseitig zu validieren – dies ist einfach möglich durch folgende schlanke und ausdrucksstarke Syntax: <input type="text" name="user.address.state" size="2" ng:required ng:validate="regexp:/^\w\w$/"/> Für weitere Informationen verweise ich auf http://angularjs.org/Overview.]]>
    /2010/08/25/angular-ein-radikal-neuer-weg-ajax-applikationen-zu-schreiben/feed/ 0
    Tutorial: Testgetriebene Entwicklung mit PHP /2010/08/23/tutorial-testgetriebene-entwicklung-mit-php/ /2010/08/23/tutorial-testgetriebene-entwicklung-mit-php/#comments Mon, 23 Aug 2010 16:24:50 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=107 Einleitung Testgetriebene Entwicklung (test driven development) ist eine Arbeitsmethodik, die Softwareentwickler dabei unterstützt, wichtige Qualitätsprinzipien bei der Erstellung von Code zu befolgen:
    • Lose Kopplung (loose couping) – weil man beim Schreiben von Unittests, dem zentralen Werkzeug der Methodik, ganz automatisch dazu verführt wird, innerhalb der Tests von Codeunits (Klassen, Methoden usw.) auszugehen, die möglichst wenige Abhängigkeiten zu anderen Modulen haben – einfach deshalb, weil das Schreiben der Tests dann zu nervig wird.
    • Saubere Trennung von Verantwortlichkeiten (separation of concerns) – aus ganz ähnlichen Gründen wie der erste Punkt: Jeder Test testet genau ein gewünschtes Verhalten, und dies führt ganz automatisch dazu, dass man später den Code, der die Tests erfüllen muss, in sauber voneinander getrennte und logisch strukturierte Einheiten teilt.
    • Schlanke Lösungen – testgetrieben bedeutet eben auch, dass man von den Tests getrieben ist, im besten Sinne: Man tut alles, um einen noch fehlschlagenden Test zu erfüllen; aber eben auch nur genau das und nicht mehr. Salopp gesagt: Man programmiert nicht mehr “einfach rum”, sondern arbeitet äußerst zielgerichtet und erzeugt Code, der nur genau das tut was er tun muss, was ganz automatisch zu einer schlanken und damit eleganten Lösung führt, in der sich zum Beispiel Bugs sehr viel schlechter verstecken können.
    Darüber hinaus hat der testgetriebene Ansatz weitere nützliche Nebeneffekte:
    • Die im Laufe der Zeit aufgebaute Sammlung von Unittests kann man benutzen, um die mit Tests versehenen Units automatisiert immer wieder testen zu können, zum Beispiel um beim Mergen eines Entwicklungszweigs mit einem anderen Zweig (oder auch nach jedem einzelnen Commit in ein Versionskontrollsystem) sicherzustellen, dass sich alle Units auch nach der Zusammenführung zweier Entwicklungslinien noch so verhalten wie erwartet. Das Stichwort für weiterführende Lektüre ist hier die Kontinuierliche Integration (continuous integration).
    • Ein Unittest ist in der Praxis nicht nur ein Stück Code, sondern immer auch Dokumentation des erwarteten Verhaltens eines Systems – zumindest in einer für Programmierer lesbaren Form. Um als Unbeteiligter ein Stück Code oder ganze Teile eines Systems kennen zu lernen, ist es häufig effizienter, die dazugehörigen Tests zu lesen, als den Code selbst.
    • Hat man erst einmal die Tests komplett geschrieben, welche die noch zu erzeugenden Units testen sollen, ist es sehr einfach, die Arbeit am eigentlichen Code einfach mittendrin auch für längere Zeit zu unterbrechen – die Tests geben einem sofort einen Anhaltspunkt, wo man “weiterprogrammieren” muss, selbst wenn man gedanklich längst aus dem Thema war.
    • Testgetrieben zu entwickeln, erzeugt ein gutes Gefühl. Das mag banal klingen, aber es ist ein realer und wichtiger Faktor. Irgendwo habe ich mal eine sehr gute Definition des Begriffs “legacy code” gelesen: “legacy code” ist Code, vor dem man sich fürchtet – weil man nicht genau weiss was er tut, und deshalb Angst hat, ihn zu verändern. Testgetriebene Entwicklung ist die beste Vorsorge gegen legacy code – man weiss, es gibt eine Instanz die überwacht und aussagt, was der Code tun soll. Es wächst das Vertrauen in den eigenen Code und damit auch in die eigenen Fähigkeiten.
    Die Unterteilung in zentrale Effekte und Nebeneffekte ist subjektiv. Ich habe die Erhöhung der Codequalität an sich für mich als wichtiger erlebt als zum Beispiel die Tatsache, dank der sich entwickelnden Testsammlung Regressionstests durchführen zu können. Geschadet hat mir jedenfalls noch kein einziger durch testgetriebene Entwicklung entstandener Effekt.

    Voraussetzungen

    Was benötigt man nun, um in PHP testgetrieben zu entwickeln? Im Wesentlichen vier Dinge:
    • Eine Arbeitsmethodik, um effizient zu testgetrieben entwickeltem Code zu kommen
    • Ein Organisationsprinzip, um Tests und zu testenden Code sinnvoll strukturieren zu können
    • Ein PHP Framework, um Testfälle schreiben zu können
    • Ein Tool, um Testfälle ausführen und auswerten zu können
    Beginnen wir mit den letzten beiden Punkten, denn dank der Maßstäbe setzenden Arbeit von Sebastian Bergmann (http://sebastian-bergmann.de/) existiert ein Softwareprojekt, welches beide Anforderungen hervorragend erfüllt und längst der de-facto Standard für Unittesting unter PHP ist: PHPUnit.

    Unter http://www.phpunit.de/manual/current/en/installation.html befindet sich eine ausführliche Anleitung für die in der Regel sehr einfache Installation.

    PHPUnit ist sowohl ein Framework aus PHP Klassen, die es erlauben, Unittests für den eigenen PHP Code zu schreiben, als auch Kommandzeilen-Werkzeug, um die eigenen Tests auszuführen und in verschiedenen Formaten die Testergebnisse darzustellen.

    Im weiteren Verlauf des Tutorials gehe ich davon aus, dass PHPUnit installiert und funktionsfähig ist.

    Im Mittelpunkt von testgetriebener Entwicklung stehen aber nicht die Werkzeuge, sondern der Arbeitsprozess. Dieser folgt stets diesem Muster:

    • Schreiben des Tests für eine neu zu implementierende Funktionalität
    • Erfüllen des Tests mit so wenig Aufwand wie möglich, so dass dieser fehlerfrei durchläuft
    • Überarbeiten des Codes, der den Test erfüllt, so dass dieser keine Duplizierungen enthält, sauber abstrahiert ist, und dem eigenen Code-Style entspricht – und dabei immer noch den Test erfüllt
    Diese Schritte werden immer wieder wiederholt, bis man keine neuen sinnvollen Tests mehr findet für die neue Funktionalität.

    Möchte man bereits vorhandene Funktionalität ändern, die bereits mit Tests versehen ist, bedeutet testgetriebene Entwicklung, dass man zuerst die Tests ändert, um das neue erwartete Verhalten widerzuspiegeln, sicherstellt, dass die veränderten Tests fehlschlagen, und dann erst den Code anpasst, um die veränderten Tests wieder zu erfüllen.

    Wäre noch die Frage der Testorganisation zu klären – einfacher ausgedrückt: Wohin mit den Tests? Meiner Meinung nach ist der einzig wirklich sinnvolle Ansatz, Code und Tests identisch zu strukturieren. Das bedeutet, der Test für die Klasse DefaultUser in lib/core/user/default_user.php sollte in der Datei tests/core/user/default_user_test.php in der Testklasse DefaultUserTest liegen.

    Aber solange wir noch kein Beispiel für einen Unittest durchgespielt haben, bleibt vieles sehr abstrakt, also beginnen wir den praktischen Teil des Tutorials.

    Ein erstes Beispiel

    Angenommen, wir möchten mithilfe von PHP ein Forum programmieren. Auf die ein oder andere Art und Weise wird diese Software eine Unit enthalten müssen, die eine E-Mail Adresse auf Gültigkeit prüft. Wir haben also eine Erwartungshaltung, was der Code später einmal tun soll. Der Einfachheit halber definieren wir diese Erwartungshaltung in diesem Beispiel so:

    Wenn eine E-Mail Adresse ohne @-Zeichen übergeben wird, dann liefere mir FALSE zurück, sonst TRUE

    Diese Erwartungshaltung gießen wir nun in Form von PHP Code in einen Unittest. Da wir testgetrieben arbeiten, existiert noch keinerlei Code der diese Erwartungen erfüllen könnte.

    Wir geben der Unit, die später einmal unsere formulierte Erwartung erfüllen soll, den Namen Verify. Daraus leitet sich als Klassenname für den Unittest die Bezeichnung VerifyTest ab.

    Wir erzeugen daher folgende Datei:

    tests/verify_test.php

    Und füllen sie mit folgendem Grundgerüst: <?php require_once('/usr/lib/php/PHPUnit/Framework.php'); class VerifyTest extends PHPUnit_Framework_TestCase {} Dieser Code repräsentiert einen Testcase, der noch keine Tests enthält. Wir inkludieren das PHP-Klassen Framework von PHPUnit, da wir unsere Testcase-Klassen von einer Klasse dieses Frameworks ableiten müssen. Je nach Plattform liegt die zu inkludierende Framework.php auch schon mal unter /usr/share/php/PHPUnit/Framework.php.

    Den Testcase selbst formulieren wir, indem wir eine Klasse definieren, deren Name auf Test endet, und die von PHPUnit_Framework_TestCase erbt.

    Dieser Testcase kann nun mithilfe des PHPUnit Kommandozeilentools ausgeführt werden. Dazu starten wir folgenden Befehl an der Kommandozeile:

    phpunit tests/verify_test.php

    Dadurch erhalten wir die folgende Ausgabe: PHPUnit 3.4.13 by Sebastian Bergmann. F Time: 0 seconds, Memory: 7.25Mb There was 1 failure: 1) Warning No tests found in class "VerifyTest". PHPUnit wertet den Testlauf als nicht erfolgreich (“Failure”), da keinerlei Tests innerhalb des Testcases gefunden wurden. Als nächstes fügen wir daher einen Test hinzu: <?php require_once('/usr/lib/php/PHPUnit/Framework.php'); class VerifyTest extends PHPUnit_Framework_TestCase { public function test_falseIfNoAtSign() { $actual = Verify::checkEmail('manuel.kiessling.net'); $this->assertFalse($actual); } } Einen Test innerhalb eines Testcase formuliert man, indem man der Testcase-Klasse eine Methode hinzufügt, deren Name mit test beginnt.
    Innerhalb der Methode schreibt man nun den Code, der notwendig ist, um den oder die Werte von der zu testenden Unit zu bekommen, mithilfe derer man das erwartete Verhalten verifizieren kann.
    Die von der Unit erhaltenen Werte testet man nun gegen eine Behauptung, einen assert: Wir drücken hier also aus, dass der Test erwartet, dass der zu testende Wert FALSE ist.

    Letztendlich muss man sich aber immer bewusst machen: Man möchte Verhalten testen, nicht Daten. Daten drücken nur das Ergebnis eines Verhaltens aus. Entsprechen die tatsächlichen (actual) Daten den erwarteten (expected) Daten, dann entspricht das tatsächliche Verhalten dem im Test erwarteten.

    Nun lassen wir den neu formulierten Testcase erneut durchlaufen, mit folgendem Ergebnis: bash$ phpunit tests/verify_test.php PHPUnit 3.4.13 by Sebastian Bergmann. PHP Fatal error: Class 'Verify' not found in tests/verify_test.php on line 8 Wenig überraschend beschwert sich PHP (nicht PHPUnit!), dass wir eine Klasse verwenden, die nirgends definiert wurde. Tun wir dies also, indem wir eine Datei lib/verify.php erzeugen und mit folgendem Inhalt füllen: < ?php class Verify {} Dann muss im Testcase noch sichergestellt werden, dass die Datei mit dieser Klasse auch inkludiert wird: <?php require_once('/usr/lib/php/PHPUnit/Framework.php'); require_once('lib/verify.php'); class VerifyTest extends PHPUnit_Framework_TestCase { public function test_falseIfNoAtSign() { $actual = Verify::checkEmail('manuel.kiessling.net'); $this->assertFalse($actual); } } Lassen wir den Testcase nun laufen, ändert sich das Bild: bash$ phpunit tests/verify_test.php PHPUnit 3.4.13 by Sebastian Bergmann. PHP Fatal error: Call to undefined method Verify::checkEmail() in tests/verify_test.php on line 9 Wir rufen eine Methode auf, die noch nicht existiert, also muss diese implementiert werden: <?php class Verify { public static function checkEmail($email) {} } Nun steht zumindest die Codestruktur komplett, so dass PHPUnit ohne Fatals durchlaufen kann: bash$ phpunit tests/verify_test.php PHPUnit 3.4.13 by Sebastian Bergmann. F Time: 0 seconds, Memory: 7.00Mb There was 1 failure: 1) VerifyTest::test_falseIfNoAtSign Failed asserting that is false. tests/verify_test.php:10 FAILURES! Tests: 1, Assertions: 1, Failures: 1. Eine Zwischenbemerkung: Das Vorgehen ist hier natürlich sehr kleinschrittig – ob man die offensichtlichen Dinge wie das Anlegen der benötigten Klassen und Methoden nicht gleich in einem Rutsch macht, bleibt Geschmackssache. Ich persönlich habe Gefallen gefunden an dem Vorgehen, meine ganze Energie in die Tests zu stecken, und dann in einen anderen Modus zu schalten und ganz stupide Schritt für Schritt immer wieder die Implementierung anzupassen und den Testlauf neu zu starten, bis keinerlei Fehler mehr auftreten.

    Wie auch immer, PHPUnit läuft nun wieder ohne PHP Fehler durch, bestätigt aber wenig überraschend, dass die nunmehr vorhandene Code-Unit nicht das Verhalten zeigt, welches wir laut Test von ihr erwarten. Wechseln wir nun also auf die inhaltliche Ebene der Implementierung und sorgen dafür, dass unser Code sich wie gewünscht verhält: <?php class Verify { public static function checkEmail($email) { if (!strstr($email, '@')) return FALSE; } } Nun besteht unser Testcase alle Tests: bash$ phpunit tests/verify_test.php PHPUnit 3.4.13 by Sebastian Bergmann. . Time: 0 seconds, Memory: 7.00Mb OK (1 test, 1 assertion) Damit wäre der erste Testzyklus komplett. Stellt sich die Frage, ob uns noch weitere Verhaltensweisen für unsere Unit einfallen, die wir von ihr erwarten. Es liegt auf der Hand, dass wir den Positivfall ebenfalls testen wollen, nämlich dass eine E-Mail Adresse mit @-Zeichen als valide erkannt wird. Natürlich würde man in der Realität noch viel mehr Ansprüche an die Validierung einer E-Mail Adresse stellen, aber in diesem Beispiel bleibe ich der Einfachheit halber unrealistisch.

    Eine Faustregel der testgetriebenen Entwicklung lautet, immer nur ein Verhalten pro Test zu überprüfen, anders ausgedrückt “ein assert pro Test”. Dies hilft, die einzelnen Tests übersichtlich und nachvollziehbar zu halten, und hat auch ganz praktischen Nutzen, da PHPUnit bei der Ausgabe eines Failures innerhalb eines Tests nicht darauf hinweist, welcher assert genau nicht erfüllt wurde, sondern immer den gesamten Test als fehlgeschlagen zu melden – hat man einen Test mit 20 asserts geschrieben, wird die Fehlersuche aufwendig.

    Formulieren wir also einen weiteren Test: <?php require_once('/usr/lib/php/PHPUnit/Framework.php'); require_once('lib/verify.php'); class VerifyTest extends PHPUnit_Framework_TestCase { public function test_falseIfNoAtSign() { $actual = Verify::checkEmail('manuel.kiessling.net'); $this->assertFalse($actual); } public function test_trueIfAtSign() { $actual = Verify::checkEmail('manuel@kiessling.net'); $this->assertTrue($actual); } } Danach sollte man allerdings, obwohl kleinschrittig, auf jeden Fall den Testcase einmal durchlaufen lassen und ihm beim Fehlschlagen zusehen: Auch beim Schreiben von Tests können Fehler passieren, und es kommt vor, dass man einen neuen Test formuliert, der wegen eines Fehlers in der Implementation oder im Test sofort erfüllt wird – geht man nach dem Schreiben des Tests sofort an die Implementation, ohne zuvor den Test einmal fehlschlagen gesehen zu haben, übersieht man möglicherweise einen Bug in der Implementation oder im Test, wenn man erst dann den Test laufen lässt und dieser dann ohne Fehler durchläuft.
    Dann sorgt gar nicht die eigene Änderung an der Implementation für das funktionieren des Tests, sondern ein Bug, den man aber eben nicht bemerkt.

    Also stellen wir sicher, dass unser neuer Test fehlschlägt: bash$ phpunit tests/verify_test.php PHPUnit 3.4.13 by Sebastian Bergmann. .F Time: 0 seconds, Memory: 7.00Mb There was 1 failure: 1) VerifyTest::test_trueIfAtSign Failed asserting that is true. tests/verify_test.php:15 FAILURES! Tests: 2, Assertions: 2, Failures: 1. Und nun ändern wir die Implementation, um ihn zu erfüllen: <?php class Verify { public static function checkEmail($email) { if (!strstr($email, '@')) return FALSE; return TRUE; } } Nun laufen beide Tests im Testcase erfolgreich durch: bash$ phpunit tests/verify_test.php PHPUnit 3.4.13 by Sebastian Bergmann. .. Time: 0 seconds, Memory: 7.00Mb OK (2 tests, 2 assertions) Das hier beschriebene Beispiel ist natürlich banal, aber im Grunde ist alles Wichtige zur Methodik der testgetriebenen Entwicklung gesagt.

    Aber auch in der eigenen Praxis, auch bei spannenden Projekten, wird man aber immer wieder dem Gefühl begegnen, dass der einzelne Test im Grunde trivial ist. Aber das ist auch völlig in Ordnung: Selbst komplexeste Softwareprojekte sind letztendlich die Verknüpfung kleiner und für sich betrachtet trivialer Funktionseinheiten – aber aus dem Zusammenspiel dieser vielen einfachen Module ergibt sich die Lösung komplexer Probleme für den Anwender.]]> /2010/08/23/tutorial-testgetriebene-entwicklung-mit-php/feed/ 0 Empfehlung: Barbecue Sauce “Bone Suckin’ regular thicker style” von Ford’s Food /2010/07/13/empfehlung-barbeque-soss-bone-suckin-sauce-regular/ /2010/07/13/empfehlung-barbeque-soss-bone-suckin-sauce-regular/#comments Tue, 13 Jul 2010 11:17:46 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=98 Die beste Sauce, die zu probieren ich bisher das Vergnügen hatte, ist jedenfalls völlig zweifelsfrei die “Bone Suckin’ Sauce regular” von Ford’s Food.

    Phil Ford war Immobilienmakler und hat aus einem Hobby heraus angefangen, diese Sauce zu entwickeln. Sie hat nur wenig Raucharoma und ist nicht scharf, im Vordergrund steht vor allem ein fantastisches Tomatenaroma und eine gewisse Süße, die es aber auch nicht übertreibt. Man muss sich sehr beherrschen, sie nicht direkt auszulöffeln.

    Die offizielle Homepage zur Sauce ist www.bonesuckin.com, zu beziehen ist sie in Deutschland zum Beispiel über BOS FOOD in Meerbusch:

    Bone Suckin´ Sauce regular, Barbecue-Sauce (dickflüssig), Ford´s Food, 454 g bei bosfood.de.]]> /2010/07/13/empfehlung-barbeque-soss-bone-suckin-sauce-regular/feed/ 0 Empfehlung: “Der Kuchenladen” in Berlin /2010/07/13/empfehlung-der-kuchenladen-in-berlin/ /2010/07/13/empfehlung-der-kuchenladen-in-berlin/#comments Tue, 13 Jul 2010 11:08:46 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=89 Das Wichtigste: Auf übertriebene effekthascherische Zuckerguß-Ungetüme wird verzichtet – die Torten zeichnet neben der spürbaren handwerklichen Qualität vor allem aus, dass sie nicht zu süß sind.

    Als Schwiegersohn einer Konditoreimeisterin bin ich sehr verwöhnt, aber der Kuchenladen hat mich noch nie enttäuscht.

    Der Kuchenladen
    Kantstraße 138
    10623 Berlin
    Telefon: 030 / 310 184 24
    E-Mail: uwe_gundelach@yahoo.de
    http://der-kuchenladen.com/
    ]]>
    /2010/07/13/empfehlung-der-kuchenladen-in-berlin/feed/ 0
    Project: PHPRestfulSubversion /2010/05/21/project-phprestfulsubversion/ /2010/05/21/project-phprestfulsubversion/#comments Fri, 21 May 2010 00:14:15 +0000 Manuel Kiessling /?p=517 PHPRestfulSubversion
    1. …provides a RESTful JSON webservice API to access information in your Subversion repository,
    2. …provides tools to cache your Subversion repository in order to make it searchable through the webservice in a fast and simple manner,
    3. …is a library of PHP classes which you can use to implement more complex use cases.

    A secondary goal of this project is to explore how to create very clean PHP code using a 100% test-driven approach.

    The source code of this project is hosted at https://github.com/ManuelKiessling/PHPRestfulSubversion

    ]]>
    /2010/05/21/project-phprestfulsubversion/feed/ 0
    Alte Homepage wieder verfügbar /2010/04/30/alte-homepage-wieder-verfugbar/ /2010/04/30/alte-homepage-wieder-verfugbar/#comments Fri, 30 Apr 2010 12:36:52 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=26 http://old.manuel.kiessling.net/ erreichbar.]]> http://old.manuel.kiessling.net/ erreichbar.]]> /2010/04/30/alte-homepage-wieder-verfugbar/feed/ 0 siqqel: SQL-Abfragen direkt aus HTML heraus ausführen und darstellen /2010/04/08/siqqel-ein-sehr-nutzliches-tool-fur-entwickler-business-analysten-produktmanager-und-qaler/ /2010/04/08/siqqel-ein-sehr-nutzliches-tool-fur-entwickler-business-analysten-produktmanager-und-qaler/#comments Wed, 07 Apr 2010 23:15:47 +0000 Manuel Kiessling http://localhost/wordpress/?p=6 siqqel.

    Welchen Zweck erfüllt siqqel?

    Die verschiedensten Leute in einem Unternehmen müssen aus den verschiedensten Gründen auf relationale Datenbanken zugreifen. Klassischerweise gibt es zwei Szenarien:

    • Ich brauche eine einfache und kurze Information
    • Beispiel: “Wie war noch gleich der ‘name’ des ‘product’ mit der Id 12345?” oder “Wieviele Einträge waren doch gleich in der ‘city’ Tabelle?”

    Üblicherweise schmeisst man dafür direkt die SQL Kommandozeile an, oder man benutzt ein Tool wie Toad, phpMyAdmin, oder irgend einen anderen Query-Browser.

    • Ich benötige eine komplexe Auswertung wichtiger Kennzahlen, inklusive historischer Betrachtung und Querverweisen, und diese brauche ich langfristig und regelmäßig
    • Beispiel: “Wir müssen die Conversions unserer User auswerten” oder “Ich brauche eine täglich aktualisierte Auswertung unserer Produktverkäufe”

    Üblicherweise werden hierfür komplexe und spezialisierte Enterprise-Tools wie Data Warehouses benutzt und manchmal auch selbst implementiert.

    Das ist auch alles fein, und die Tools für beide Szenarien sind vielfältig und ausgereift. In der Praxis gibt es aber ein weiteres Szenario, welches sozusagen “dazwischen” liegt: Hier ein paar Beispiele:

    • Die QA Abteilung soll einem Bug nachspüren und muss dafür über einen Zeitraum von einigen Tagen einige mittelkomplexe Datenanalysen fahren und diese regelmäßig aktualisieren (“zu welcher Tageszeit kommt es vor dass User aus Gruppe X auf Seite Y Aktion Z durchführen, und dann die Kombination der Daten aus Tabelle A, B, und C gleich D ergibt?”)
    • Ein Produktmanager soll ein neues Feature konzeptionieren und benötigt dafür über einen sehr begrenzten Zeitraum eine Auswertung über verschiedene Business-Kennzahlen. Da die Analyse auf ganz neuen Annahmen beruht, helfen die im Data Warehouse vorhandenen Reports nicht weiter.
    • Ein Softwareentwickler arbeitet an der Anbindung eines externen Webservice, und möchte während der Implementations- und Testphase alle Tabellen und die zusammengehörenden Daten, die aus Webservice-Calls resultieren, im Blick haben, ohne jedes Mal 30 einzelne Queries abfeuern und miteinander in Verbindung bringen zu müssen.
    • Ein Business Analyst soll einen größeren Report vorbereiten, möchte aber erst mal ein Gefühl dafür bekommen welche Daten er benötigt und wie er diese sinnvoll miteinander verknüpfen kann.

    Alle diese Beispiele haben eines gemeinsam: Die “kleine” Lösung, direkt einzelne Queries nacheinander an die DB zu schicken und die Ergebnisse dann händisch zusammenzutragen und miteinander in Verbindung zu bringen, ist zu klein, damit zu anstrengend und ineffektiv. Man kennt das, man fängt dann an sich die Queries in irgendein Textfile zu pasten damit sie nicht verloren gehen, oder man hat in Tools wie phpmyadmin plötzlich 15 Browsertabs auf und wird langsam wahnsinnig.

    Die “große” Lösung ist aber wiederum zu groß:  Es lohnt in der Regel nicht, einen Business-Analysten mehrere Stunden oder Wochen mit dem Bau eines Reports aus dem Data Warehouse zu beauftragen, nur weil man wenige Tage lang etwas beobachten oder nur vorübergehend Daten debuggen muss.

    Der Kompromiss sieht dann häufig so aus, dass man anfängt eine Zwischen-Notlösung auf irgend einer Insel zu bauen: Man fängt an, mit irgendwelchen ODBC Kontrukten und Excel. Schick mir so eine Excel Datei, und ich sehe nichts, denn ich habe ODBC gerade nicht richtig eingerichtet. Oder der Produktmanager, der seine temporäre, aber komplexe Auswertung braucht, bekommt eine virtuelle Maschine mit einer Basisinstallation von PHP, ein Developer gibt ihm einen Crash-Kurs in PHP-Entwicklung, und los geht das Gefrickel. Irgendwo fliegen dann diese Skripte rum, nach ein paar Monaten, wo sie vielleicht für eine neue, ähnliche Analyse noch mal nützlich gewesen wären, findet sie dann auch keiner mehr. Der PM schlägt sich mit Programmierung rum, Sysops meckert zu Recht, dass sie jetzt auch noch diese Spielkiste managen müssen, alle sind unglücklich, und irgendwo in der Ferne fängt ein kleines Kind an zu weinen.

    Das muss nicht sein!

    Denn genau diese Nische zwischen “einfach mal ein Query” und “das große böse komplette Data Warehouse” besetzt siqqel exzellent, ohne die Probleme der frickeligen Insellösungen einzuführen.

    Wie funktioniert siqqel?

    Die Mächtigkeit von siqqel liegt darin, dass es den Applikationsstack, der benötigt wird, um Anfragen an die Datenbank zu übermitteln, die Antwort entgegenzunehmen und die empfangenen Daten darzustellen, auf etwas recht bekanntes und verbreitetes beschränkt: den Browser.

    SQL Queries werden direkt in einer statischen HTML Datei notiert. Per Ajax werden diese an ein zentral abgelegtes Backend-Skript übermittelt. Das Result Set wird an den Browser zurückgeliefert und direkt dort per DHTML dargestellt. Mit (D)HTML Bordmitteln, JavaScript und CSS kann man direkt innerhalb des HTML Dokuments dann beliebig flexibel mit den Result Sets arbeiten. Richtig, ganz ohne PHP geht es nicht. Es braucht einen Punkt im Backend, welcher den SQL Query vom Browser entgegennimmt, an die DB übermittelt, und das Result Set als JSON an den Browser zurückliefert. Aber man beachte die Vorteile zur vorhin beschriebenen Insellösung:

    • Das Skript wird einmalig an zentraler Stelle in der Serverlandschaft hinterlegt – zum Beispiel an dieselbe Location, an der bereits der phpMyAdmin läuft; dann hat man vielleicht sogar gleich die Frage der Zugriffsrechte erschlagen, denn (üblicherweise) haben nur die richtigen Personen im Unternehmen Zugriff auf diese Ressource, und Sicherheitsmechanismen, die für die Zugriffsicherung des phpMyAdmin bereits implementiert wurden (wie .htaccess, SSL Public Keys etc.), greifen ohne zusätzlich notwendige Handgriffe auch für das PHP Backend von siqqel.
    • Nun kann jeder sofort anfangen, Reports auf Basis von siqqel zu bauen – alles was er braucht: Zugriffsrecht auf die HTTP Location des PHP Backend Skripts – und einen Browser!

    Wie funktioniert das nun im Detail?

    Angenommen, es gibt im Intranet eine MySQL Datenbank mit einer Tabelle, in der stehen alle Produkte des Unternehmens. Nennen wir sie ‘product’, und nehmen an sie befindet sich im Schema ‘data’. Nehmen wir weiterhin an, es gibt einen Server, auf dem wurde phpmyadmin installiert, damit man über diese Datenbank browsen kann. Dieses ist erreichbar unter unter http://intranet/secure/phpmyadmin. /secure ist der mit Zugriffsrechten versehene Teil des Servers. Nun muss ein Systemadministrator die PHP Backendskripte unter http://intranet/secure/siqqel/ hinterlegen, und die Konfiguration anpassen um dem siqqel PHP Code Zugriff auf die genannte Datenbank zu ermöglichen. Ein siqqel User muss dann nur eine HTML Datei erzeugen (auf seinem Desktop oder wo auch immer, ein LAMP Kontext wird ja nicht benötigt), die folgendes enthält: <!DOCTYPE html> <html> <head> <script type="text/javascript" src="http://intranet/secure/siqqel/siqqel.js.php"> </script> </head> <body> <table sql="SELECT * FROM data.product"></table> </body> Öffnet er diese Datei lokal in seinem Browser, wird das SQL Statement im Attribut der Table an das Backend Skript übermittelt, das Result Set als JSON zurückgegeben, und der Inhalt der Datenbanktabelle automatisch in das table Element gerendert.

    Von hier aus hat man alle Möglichkeiten: Man möchte mehrere Tabellen auf einmal anzeigen? Man erzeugt einfach mehrere table Elemente mit den entsprechenden Queries. Man möchte alle Zeilen im Result Set, bei denen die Spalte name mit “a” beginnt in der HTML Tabelle hervorheben? Kein Problem, jede Tabelle, Zeile und Spalte liefert ein “loaded” Event, also hat man mit einem JavaScript-Konstrukt wie $('td.name').live('loaded', function(name) { // do something useful. }); alle Möglichkeiten. Der Client Teil von siqqel basiert auf jQuery, also kann man schnell und einfach Reports bauen mit allen sinnvollen und sinnlosen Möglichkeiten, die jQuery bietet.

    Was sind die weiteren Vorteile? Nun, die HTML Datei ist nicht nur der View des Reports, die HTML Datei IST der Report. Man kann ihn in die vielleicht vorhandenen Coderepositories im Unternehmen packen, man kann ihn per Mail verschicken, man, wenn die Wikisoftware es zulässt, seine Reports sogar direkt nativ in eine Wikiseite packen und so besonders effizient mit den Kollegen im Unternehmen teilen. Die Projektseite von siqqel ist http://github.com/MyHammerOpenSource/siqqel. Nicht wundern, bis vor kurzem hieß das Projekt noch “sqlHammer”, der Begriff mag noch an verschiedenen Stellen auftauchen. Bei Fragen zu siqqel empfehle ich, ein Issue Ticket bei github zu öffnen, oder wendet euch an opensource@myhammer.com.]]> /2010/04/08/siqqel-ein-sehr-nutzliches-tool-fur-entwickler-business-analysten-produktmanager-und-qaler/feed/ 0 Database Change Management mithilfe von VCS: Teil 1 /2010/02/26/database-change-management-mithilfe-von-vcs-teil-1/ /2010/02/26/database-change-management-mithilfe-von-vcs-teil-1/#comments Fri, 26 Feb 2010 12:39:01 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=28 Dieser Artikel ist Work in Progress!

    Vorüberlegungen

    Dieses Dokument beschreibt Werkzeuge und Prozesse, um Datenbankänderungen innerhalb von großen Softwareprojekten einfach, fehlerfrei und nachvollziehbar durchzuführen und zu managen. Zentraler Ansatz dieser Lösung ist: Datenbankänderungen und Codeänderungen sind prinzipiell genau dasselbe. Denn Datenbankänderungen haben genau wie Codeänderung die folgenden Eigenschaften:
    • Sie ändern das Verhalten des Softwaresystems
    • Sie entwickeln sich verteilt in verschiedenen Projekten bzw. Branches, und müssen für Abnahme und Rollout/Release zusammengeführt werden
    • Beim Zusammenführen kann es Überschneidungen und Konflikte geben, die man mitbekommen und lösen können möchte
    • Man möchte sie auch später noch nachvollziehen können, also sehen wer wann was gemacht hat
    • Man möchte diese Änderungen ggf. einem Reviewprozess unterziehen
    Wenn wir Datenbankänderungen in diesem Sinne genau wie Codeänderungen verstehen, macht es auch Sinn, Datenbankänderungen genau wie Codeänderungen zu behandeln. Und das bedeutet, diese innerhalb des bereits vorhandenen Entwicklungsprozesses zu managen und im selben VCS Repository zu verwalten.

    Abbildung der Datenbankänderungen im VCS

    Unter Datenbankänderungen müssen wir verstehen: Alle SQL Statements, welche die Strukturen oder Inhalte einer Datenbank verändern. Eine Datenbankänderung im Zuge eines Projekts, Bugfixes oder sonstigen Tickets ist daher folgerichtig eine Sammlung von SQL Statements, welche zusammen mit den Codeänderungen des zugehörigen Tickets im selben Branch vom Entwickler hinterlegt wird. Hinzu kommt, dass es eine klar definierte Lokalität für diese Änderung geben muss, damit ein Raum geschaffen ist, in dem Konflikte entstehen (und gelöst werden) können. So wie die gleichzeitige Änderung an der Datei myFile.txt in zwei verschiedenen, zu mergenden Branches zu einem Konflikt führt – da in beiden Branches die Datei den selben Speicherort, also dieselbe Lokalität besitzt – müssen auch Änderungen an derselben Tabelle in zwei Branches innerhalb derselben Lokalität des jeweiligen Branches stattfinden. Der vorgeschlagene Ansatz ist daher, die Struktur der Datenbank, also die Databases mit den darunterliegenden Tables, in einer analog aufgebauten Ordner-Datei-Struktur abzubilden. Die Lokalität für die Tabelle users.hobbies wäre beispielsweise die Datei /dbchanges/users/hobbies.sql innerhalb des VCS. Abgebildet wird die gesamte DB Struktur, also alle Databases mit allen ihren Tables: /dbchanges/users/hobbies.sql /dbchanges/users/contact.sql ... /dbchanges/products/colors.sql /dbchanges/products/forms.sql ... und so weiter. Gerade bei komplexen Datenbanken macht es natürlich Sinn, diese Struktur mit einem Skript zu erzeugen, für MySQL kann man dazu in einem beliebigen Verzeichnis auf dem DB Server folgenden Code ausführen (geht davon aus, dass die MySQL Daten unterhalb /var/lib/mysql liegen): find /var/lib/mysql -type f -name *.frm -exec dirname {} \;| cut -d "/" -f 5| xargs mkdir -pfind /var/lib/mysql -type f -name *.frm | cut -d "/" -f 5,6 | sed "s/.frm/.sql/g" | xargs touch Diese Dateien nenne ich im folgenden DB Change Container.

    Prozessbeschreibung

    Während der Produktion eines neuen Release

    Wichtig ist, dass sämtliche DB Change Container nach einem Release, nachdem diese Änderungen also auf dem Produktivsystem angewendet wurden, wieder leer sind – denn zum Start der Produktion eines neuen Releases liegen noch keine neuen Änderungen für die DB vor. Nun beginnen die Entwickler, Tickets (Feature Requests, Bugs etc.) umzusetzen, einige gemeinsam in einem Branch, einige in eigenen Branches. Sind im Zuge einer Implementation Datenbankänderungen notwendig, hinterlegt der Entwickler innerhalb des zugehörigen Branches diese Änderungen nach folgendem Muster:
    • Case 1: Die Tabelle user.hobbies soll verändert werden (neues Feld, Feld löschen, Index anlegen oder löschen, einfügen, löschen oder ändern von Einträgen etc.) Der Entwickler legt alle benötigten Statements in der Datei /dbchanges/users/hobbies.sql ab: USE users; ALTER TABLE hobbies ADD newfield1 INT NOT NULL AFTER userId; ALTER TABLE hobbies DROP oldfield; ALTER TABLE hobbies ADD newfield2 TINYINT NOT NULL; ALTER TABLE hobbies ADD INDEX (newfield2); INSERT INTO hobbies ( id, name, value ) VALUES (1234, 'hobbyname', 'hobbyvalue');
    • Case 2: Der Entwickler legt eine komplett neue Tabelle pets im vorhandenen Schema users an Er erzeugt dazu eine neue Datei /dbchanges/users/pets.sql und füllt sie mit dem CREATE Statement (sowie ggf. INSERT Statements): USE users; CREATE TABLE pets( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, petname VARCHAR( 64 ) NOT NULL, FULLTEXT ( petname ) );
    • Case 3: Der Entwickler legt eine neue Database products und darin eine neue Tabelle colors an Er erzeugt einen neuen Ordner /dbchanges/products und darin eine Datei colors.sql mit folgendem Inhalt: CREATE DATABASE products; USE products; CREATE TABLE colors ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, colorname VARCHAR( 24 ) NOT NULL);
    • Case 4: Der Entwickler löscht die Tabelle colors in der Database products Er füllt die Datei /dbchanges/products/colors.sql mit folgendem Inhalt: USE products; DROP TABLE colors;
    Ansonsten läuft der Entwicklungsprozess wie gewohnt.

    Merge aller Tickets für den Release

    Werden nun verschiedene Tickets für den Release gebündelt, werden die einzelnen Branches wie gehabt gemerged. In Hinblick auf die DB Änderungen passiert nun folgendes: Sämtliche Änderungen in den einzelnen Branches unterhalb von /dbchanges werden naturgemäß unterhalb /dbchanges im Merge zusammengeführt. Hierbei greifen die bekannten VCS Mechanismen: Wurden Änderungen in einer Datei nur in einem einzigen Branch oder Commit vorgenommen, werden diese Änderungen einfach angewendet. Wurden Änderungen an einer Datei (also innerhalb derselben Lokalität) in mehreren Branches vorgenommen, kommt es zu einem Konflikt. Dies ist der erste wichtige Mechanismus der hilft, die drei Anforderungen – einfach, fehlerfrei und nachvollziehbar – zu gewährleisten: Da der Konflikt garantiert eintritt, ist auch garantiert, dass der Vorgang völlig automatisch die notwendige Aufmerksamkeit erzeugt und nicht übersehen werden kann. Nun muss, wie auch bei Codekonflikten, gelöst werden: Machen beide Änderungen Sinn, oder widersprechen sie sich? Wie genau kann man sie am sinnvollsten zusammenführen? Relevant ist hier nur, dass am Ende ein Set an Änderungsanweisungen in den Approval committet wird, welches in sich rund ist. Falls es eine eigene Test oder QA Datenbank gibt auf die diese Änderungen angewendet werden müssen, wird dies gemacht nachdem alle Tickets fertig gemerged wurden.

    Durchführung des Release

    Wurde im Vorfeld alles richtig gemacht, muss im Zuge des Rollout oder Release nur noch das zusammengefasste Set an Änderungen ermittelt werden, und diese müssen dann, entsprechend ihrer jeweiligen Eigenschaft, ausgeführt werden. Die Summe der Änderungen ergibt sich aus der Summe aller Anweisungen in den DB Change Containern unterhalb /dbchanges – hier macht es natürlich Sinn, dass man diese mithilfe eines Skripts “zusammensammelt”, aber ich gehe hier nicht näher darauf ein. Nach dem Rollout/Release, und vor dem Erzeugen neuer Branches, müssen dann im Trunk sämtliche Datenbank-Änderungsanweisungen aus den DB Change Containern entfernt werden (auch hier macht ein Skript wie z.B. for f in `find . -type f -name *.sql`; do echo -n "" > $f; done Sinn, um diesen Schritt zu vereinfachen), und dies muss in den Trunk (oder von wo aus auch immer neue Branches gebildet werden) committet werden – denn sonst würden dieselben Änderungen beim nächsten Rollout erneut angewendet werden. ]]>
    /2010/02/26/database-change-management-mithilfe-von-vcs-teil-1/feed/ 0
    Wie man Replikationsunterbrechung durch Deadlocks bei INSERT INTO … SELECT verhindert /2007/08/07/wie-man-replikationsunterbrechung-durch-deadlocks-bei-insert-into-select-verhindert/ /2007/08/07/wie-man-replikationsunterbrechung-durch-deadlocks-bei-insert-into-select-verhindert/#comments Tue, 07 Aug 2007 13:04:17 +0000 Manuel Kiessling http://172.16.111.147/wordpress/?p=36 My-Hammer Auftragsradar, der unsere Auftragnehmer auf Wunsch regelmässig per E-Mail über neu eingestellte Auktionen anhand einstellbarer Filterkriterien informiert, baut bei jedem Durchlauf eine eigene Suchtabelle auf. Diese wird gefüllt mit einer Untermenge der Daten unserer Haupt-Auktionstabelle, nämlich nur den derzeit laufenden Auktionen. Die Verwendung von INSERT INTO … SELECT ist hier naheliegend, zum Beispiel so:

    INSERT INTO Suchtabelle
     SELECT a, b, c FROM Auktionstabelle WHERE x = y

    Es ergab sich folgendes Problem: Der Query wird wie jeder andere auch auf die Datenbankslaves repliziert. Dort wurde er auch korrekt ausgeführt. Jedoch nicht immer auf dem Master: hier kam es regelmäßig zu Deadlocks auf der Auktionstabelle, da dies eine InnoDB Tabelle ist (bei MyISAM Tabellen können Deadlocks nicht auftreten). Wenn ein MySQL Slave jedoch feststellt, dass beim gleichen Query auf dem Master und auf dem Slave unterschiedliche Fehler auftreten (Slave: no error; Master: deadlock), unterbricht dieser die Replikation. Es hilft dann nur ein SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE;. Ich habe mich daraufhin nach Lösungen umgeschaut. Erste Anlaufstelle ist das Kapitel Vom Umgang mit Deadlocks im MySQL Handbuch. Mein erster Versuch war, den 4. Tipp dieses Kapitels zu befolgen: Das Einstellen eines niedrigeren Isolationslevels. Da perfekte Datenkonsistenz für die benötigte Suchtabelle nicht nötig ist (dirty reads also akzeptabel sind), verwendete ich gleich den niedrigsten Level READ UNCOMMITED. Das Ergebnis war gelinde gesagt verheerend, es traten noch mehr Deadlocks auf als zuvor. Deshalb bin ich dazu übergegangen, die beteiligten Tabellen explizit mit einem READ LOCK zu sperren – viele Artikel zu diesem Thema haken diese Vorgehensweise sofort als nicht gangbar ab, da die Performance darunter leide. Da es sich beim Auftragsradar jedoch um einen Cronjob handelt, der nur alle paar Minuten einmal läuft, und der INSERT INTO … SELECT Query sehr schnell durchläuft, erschien mir das Risiko, eine unserer wichtigsten Tabellen für diesen Query zu sperren, als gering. Wie sich zeigte, brachte dies den gewünschten Erfolg: Seitdem sind an dieser Stelle keinerlei Deadlocks mehr aufgetreten, und der Rest der Plattform zeigt sich von den seltenen und kurzen Locks völlig unbeeindruckt.]]>
    /2007/08/07/wie-man-replikationsunterbrechung-durch-deadlocks-bei-insert-into-select-verhindert/feed/ 0
    Recycelter Artikel: “My-Hammer, das Fernsehen und die Serverlast” /2007/07/17/recycelter-artikel-my-hammer-das-fernsehen-und-die-serverlast/ /2007/07/17/recycelter-artikel-my-hammer-das-fernsehen-und-die-serverlast/#comments Mon, 16 Jul 2007 23:22:28 +0000 Manuel Kiessling http://localhost/wordpress/?p=13 Vor mittlerweile auch schon wieder einer halben Ewigkeit hatte ich mal eine kurze Artikelserie zum Thema Serverlast-Problemlösungen bei MyHammer online, die ich nun wieder ausgegraben habe. Vieles entspricht gar nicht mehr den aktuell bei MyHammer eingesetzten Lösungen, aber verwahrenswert finde ich den Schrieb allemal. Leider fehlen die Grafiken, vielleicht finde ich die noch mal irgendwo.

    Hier der Artikel:

    Vergangenen Donnerstag zeigte das ProSieben Magazin Galileo einen ca. 10-minütigen Beitrag über My-Hammer (kurze Infos zur Sendung hier). Vom Ansatz her ging es um “Branchenbuch vs. My-Hammer”, aber für die Betrachtung hier ist das gar nicht so sehr von Interesse – es ist noch nichtmal von Interesse, ob so ein Beitrag positiv oder negativ für uns ist (in dem Fall war’s wie fast immer positiv) – sobald das Magazin, in dem über uns berichtet wird, genug Reichweite hat, schießen die Zugriffe in die Höhe. Die wichtigste Erkenntnis, die wir immer wieder machen: zumindest bei den Privaten scheinen die Zuschauer sprichwörtlich mit dem Laptop auf den Knien vorm Fernseher zu sitzen. Die Zugriffe kommen extrem schnell und gebündelt (beim Galileo-Beitrag war aber interessant, dass die Zugriffe wieder auf einen Schlag kamen, aber erst in dem Moment, in dem der Beitrag vorbei war).

    Genau dieses plötzliche Auftreten so vieler Zugriffe ist natürlich die Herausforderung – dieselbe Anzahl User auf nur 15 Minuten verteilt wären kein Problem, aber TV sorgt dafür, dass das meiste innerhalb der ersten 5 Minuten passiert. Und es ist wirtschaftlich natürlich ziemlich unvernünftig, die für diese 5 Minuten benötigte Rechenpower anzuschaffen, nur damit sie die anderen 525.595 Minuten im Jahr vor sich hindümpelt.

    Trotzdem kann man eine Webseite auch auf solche Extremsituationen vorbereiten – My-Hammer hat am Donnerstag perfekt standgehalten, lediglich eine leichte Verzögerung in den Ladezeiten war während der kritischen Phase spürbar.

    Um kurz die Dimensionen klarzumachen, erstmal eine Grafik, welche den ein- und ausgehenden IP Traffic für unser Netzwerk anzeigt. Man sieht sehr deutlich den Sprung auf das gut 2,5-fache des normalen Werts. Der Faktor selbst klingt vielleicht erstmal nicht so dramatisch, aber wie erwähnt geht es nicht um die Masse an sich, sondern das extrem gebündelte Auftreten dieser Masse an Zugriffen:

    (Die Grafik ist leider nicht mehr auffindbar)

    Ich behaupte mal, man erkennt recht gut, wann die Sendung lief…

    Also, wie kann man die Serversysteme auf so etwas vorbereiten? Klar: mehr Server kaufen. Das ist durchaus ein Aspekt, aber nicht das Allheilmittel. Vor allen Dingen kann das sehr ineffektiv und unwirtschaftlich sein. Angenommen, man hat Server A mit einer gewissen Leistungsfähigkeit. Nun kann man sich Server B mit doppelt so schnellem Prozessor, doppeltem Arbeitsspeicher und doppelt so schnellen Festplatten kaufen. Dann hat man schon Unmengen von Geld ausgegeben, und hat gerade mal eine Steigerung der Leistungsfähigkeit von 100% (mal davon abgesehen, dass die Rechnung “doppelt so schnelle Hardware, doppelt so viel Leistung” in der Praxis auch nicht wirklich hinhaut). Dagegen kann ein einziger geschickt gesetzter Index in der Datenbank manchmal 1000% bessere Performance bringen, ohne dass man etwas an der Hardware tut.

    Wenn man den Anschaffungspreis neuer Hardware mal auf den Stundenlohn eines Entwicklers umrechnet, wird man schnell zu dem Schluss kommen, dass es sich auch finanziell durchaus rechnen kann, diesen einige Tage lang auf die Datenbank anzusetzen um zu schauen, ob nicht doch irgendwo ein wichtiger Index vergessen wurde oder einige Tabellenstrukturen besser ganz anders aufgebaut sein sollten.

    Das sind nur ein paar grundsätzliche Überlegungen. Spürbaren Erfolg wird man nur haben, wenn man ein ganzes Bündel an Massnahmen ergreift und vor allem immer das Gesamtsystem vom Code über die Datenbank bis hin zu den Servern und dem Netzwerk im Überblick hat. Die vielleicht wichtigste Faustregel, wenn man über Performanceoptimierung von Webseiten spricht, scheint mir daher zu sein: Coder und Admins an einen Tisch! Es hilft nichts, wenn die Entwickler meinen, die Geschwindigkeit des Systems sei doch schliesslich Sache des Admins. Umgekehrt ist es extrem hilfreich, wenn die Programmierer auch einen gewissen Sysadmin-Background haben, und die Admins umgekehrt auch Programmiererfahrung haben; was bei uns glücklicherweise sogar sehr ausgeprägt der Fall ist.

    Die weiteren Teile befassen sich mit den konkreten Massnahmen, die man ergreifen kann um sich auf einen TV Beitrag vorzubereiten. Hinweis: Thematisch durchaus verwandt berichtet Tom Bachem über die Systemarchitektur von sevenload.

    Welche Massnahmen kann man nun konkret ergreifen, um sich auf einen TV Beitrag über die eigene Webseite vorzubereiten? Ich versuche so allgemein wie möglich zu bleiben, aber da es um konkrete Ratschläge gehen soll und ich holprige Umschreibungen vermeiden möchte, wird das Vokabular ab jetzt etwas LAMP-lastig; bitte entsprechend auf die eigene Technik ummünzen.

    Massnahme 1: Datenbankoptimierung

    Wurde ja schon erwähnt: die Indizes. Ich verrate wahrscheinlich nicht einmal DB Anfängern etwas neues, wenn ich betone, dass dies essentiell ist. Wenn man die Indizes nicht im Griff hat, braucht man sich die anderen Punkte noch gar nicht anschauen. Deshalb: Ins Slow-Log gucken. Vor allem: Immer wieder. Einen Status Quo gibt es nicht! Immer wieder EXPLAIN bemühen, vom stumpf auf die Strukturen in phpMyAdmin gucken findet man die Performancefresser nicht.

    Es gibt diese missverständliche Formel “Braucht man Geschwindigkeit, nimmt man MyISAM, braucht man Sicherheit, InnoDB”. InnoDB ist nicht nur einen Blick wert, wenn man Transaktionssicherheit braucht. Im Gegensatz zu MyISAM lockt InnoDB bei schreibenden Queries immer nur die betreffenden Zeilen, MyISAM dagegen grundsätzlich die gesamte Tabelle. InnoDB hat zwar aufgrund der größeren Komplexität etwas mehr “Grundoverhead”, aber das intelligentere Locking kann immens wertvoll sein in bestimmten Szenarien und das mehr als wettmachen. Wenn man eine Tabelle hat die man hinsichtlich Struktur und Indices schon perfekt durchoptimiert hat (genau das aber wiederum erstmal sicherstellen!), und trotzdem tauchen Queries auf diese Tabelle immer noch im Slow Log auf, dann sollte man prüfen, ob diese Queries vielleicht immer auf einen Lock warten. In diesem Fall InnoDB auf jeden Fall eine Chance geben. Das hat bei uns konkret bei den Session und Cachetabellen (dazu später mehr) enorm viel gebracht, weil dort die Lese- und Schreibzugriffe ein ausgewogenes Verhältnis haben.

    Ein Aspekt, der wenig berücksichtigt wird, ist die Größe der Felder, auf die man Indices setzt. Es kann sich lohnen, hier sparsam zu sein, denn ein kleinerer Spaltentyp bedeutet auch weniger Speicherplatzverbrauch für den Index auf diese Spalte, und das kann im Zweifel nur gut (= schneller) sein. Man ist halt geneigt, seine Primary IDs immer als INT anzulegen. Aber nehmen wir mal den Klassiker Benutzertabelle: Wird man wirklich in nächster Zeit 4 Milliarden User haben? Das dürfte selbst bei eBay noch ein bisschen dauern. Erstmal tut es also auch ein MEDIUMINT, setzt man diesen UNSIGNED, ist das Limit bei 16 Millionen. Hat man soviele User, bewegt man sich wohl eh in völlig anderen Dimensionen.

    Zumal das Umwandeln einer Spalte in einen Typ mit größerem Wertbereich (also z.B. von MEDIUMINT nach INT) unproblematisch ist. Wichtig ist allerdings auch, dass man sämtliche Felder, die einen Fremdschlüssel auf ein MEDIUMINT Feld darstellen, ebenfalls als MEDIUMINT anlegt, sonst hat man bei Joins nichts gewonnen.

    Was bei der Skalierung von MySQL immer enorm hilft ist Replikation. Dazu wurde schon so viel geschrieben, dass ich mir die Wiederholung spare, nur dies: Wir fahren bisher sehr gut damit, das Balancing der Nur-Lese Zugriffe direkt in unserer Applikation zu regeln, und nicht über einen eigenen Software- oder Hardware-Loadbalancer. Da bei fast jedem Seitenaufruf der Master sowieso früher oder später konnektiert werden muss, kann man diese Verbindung auch nutzen, um MASTER STATUS und SLAVE STATUS zu vergleichen, um so ein Fallback auf den Master zu realisieren, falls alle Slaves einmal mehr als 0 Sekunden hinter dem Master zurückhängen. Was sich übrigens ziemlich gut vermeiden lässt, wenn man Master und Slaves per Gigabit statt Fast Ethernet anbindet.

    Ein oft nicht wahrgenommener Vorteil von Replikation: Man kann einen Slave für’s Backup bereitstellen, auf dem man die Datenbank stoppen und auf Dateisystemebene wegkopieren kann (oder man hält nur den Slave Thread an und macht einen Dump), so dass man einen sauberen Snapshot der Datenbank hat, ohne das Gesamtsystem anhalten zu müssen.

    Ein weiterer wichtiger Hebel für die Skalierung ist es, für spezielle Aufgaben jeweils eigene DB Server bereitzustellen, z.B. ein oder mehrere Maschinen nur für die Sessiontabellen, nur für Tabellen mit Cache-Inhalten, nur für Logtabellen; prinzipiell kann jede Tabelle, die nicht in Form von Joins oder Subselects zusammen mit anderen Tabellen gleichzeitig abgefragt werden muss, auch getrennt von den anderen Tabellen auf einem eigenen Server liegen. Darüber hinaus macht die Trennung von sehr verschiedenen Tabellen wie Session- und Logtabellen alleine deshalb schon Sinn, weil man dann die Datenbanksoftware für diese speziellen Aufgaben optimieren kann.

    Eine praxisnahe Zusammenstellung der Massnahmen, die sich bei My-Hammer.de bewährt haben:

    InnoDB vs MyISAM

    Ich schrieb bereits, dass man InnoDB nicht nur dann in Erwägung ziehen sollte, wenn man Transaktionssicherheit benötigt. Eine Tabelle von MyISAM auf InnoDB umzustellen kann unter Umständen Geschwindigkeitsvorteile bringen, nämlich dann, wenn das zweite wichtige Feature von InnoDB neben der Transaktionssicherheit, das Row Level Locking, effektiv zum Zug kommen kann. Um herauszufinden, ob dies der Fall ist, kann man wie folgt vorgehen:

    Mitloggen aller Queries

    Wenn man für einen bestimmten Zeitraum (bei einer gut besuchten Seite reichen wenige Minuten) einmal alle Abfragen, die an die Datenbank gestellt werden, mitschreibt, kann man aus diesem Log eine Menge interessanter Informationen ziehen. Um festzustellen, ob eine Tabelle vom Row Level Locking profitieren könnte, muss man die lesenden (SELECT) und schreibenden (INSERT, UPDATE, DELETE etc.) Abfragen gegenüberstellen.

    Wird aus einer Tabelle sehr häufig gelesen, die Daten in der Tabelle aber nur sehr selten verändert, dann macht das Table Level Locking von MyISAM in der Regel keine Probleme: Zwar wird bei einem UPDATE, INSERT oder DELETE die gesamte Tabelle für nachfolgende Lesezugriffe gesperrt (d.h. diese müssen warten), bis der Schreibprozess abgeschlossen ist. Aber da dies nur selten geschieht, kommt es auch selten vor, dass ein Leseprozess warten muss, so dass daraus keine spürbare Verzögerung im Gesamtsystem resultiert.

    Gleiches gilt im umgekehrten Fall: Wird in eine Tabelle praktisch nur geschrieben, aber selten daraus gelesen (wie es z.B. bei Logtabellen häufig der Fall ist), dann kollidieren auch hier die “Interessen” nur so selten, dass nicht mit Performanceeinbußen zu rechnen ist.

    Slow Log

    Interessant sind also jene Tabellen, bei denen Schreib- und Lesezugriffe in einem ausgeglicheneren Verhältnis stehen. In welcher Relation die beiden Zugriffsarten dabei mindestens stehen müssen, damit es sich “lohnt” InnoDB einzusetzen, ist schwer zu sagen. Ein Blick ins Slow-Log von MySQL hilft hier weiter: Wenn man immer wieder bei denselben Tabellen auf langsame Queries stösst, die nicht wegen des Queries selbst langsam waren, sondern weil sie auf ein Lock warten mussten, hat man auf jeden Fall aussichtsreiche Kandidaten.

    SHOW PROCESSLIST

    Eine weitere Methode ist, sich einmal für einige Minuten immer wieder die Liste der laufenden Prozesse in MySQL auflisten zu lassen (SHOW PROCESSLIST). Wenn man dort immer wieder dieselben Queries sieht, deren Status Locked ist, dann weiss man wo das Problem liegt. Diese Methode mag zwar auf den ersten Blick wie ein Glücksspiel wirken, aber gerade weil man immer nur die Prozesse sieht, die zufällig gerade laufen wenn man den Befehl absetzt, fallen die problematischen Prozesse erst recht auf, die immer wiederkehren und oft vielleicht sogar während zwei oder mehr SHOW Aufrufen immer noch laufen. Meiner Meinung nach die schnellste Methode, Flaschenhälse zu finden.

    Mehr zum Thema Locking gibt es im Kapitel ‘Internal Locking Methods’ des MySQL Handbuchs.

    Nehmen wir also an, man hat einige Tabellen identifiziert, bei denen Queries öfter als gesund ist auf einen Lock warten müssen. Dies könnte beispielsweise eine Sessiontabelle sein (falls man z.B. PHP nutzt und die Sessionfunktionen so angepasst hat, dass diese eine MySQL Datenbank als Storage nutzen, ein ziemlich klassisches Szenario). Diese Tabelle wird bei jedem Seitenaufruf zu Beginn einmal gelesen, um die Session des aufrufenden Benutzers zu laden, und am Ende des Skripts wird der Sessioninhalt dieses Benutzers wieder geschrieben. Also ein sehr ausgewogenes Verhältnis zwischen lesenden und schreibenden Zugriffen – jeder Seitenaufruf, der gerade an dem Punkt angelangt ist, an dem die Session geschrieben wird, würde also die Tabelle sperren für sämtliche anderen Seitenaufrufe, die in diesem Moment aus der Sessiontabelle lesen möchten – das Performanceproblem ist ab einer bestimmten Anzahl von gleichzeitigen Benutzern vorprogrammiert.

    Klassischerweise geht man nun so vor, dass man die Tabelle in InnoDB umwandelt und wieder einige Zeit das Slow Log oder die Prozessliste beobachtet – sinkt die Lock_Time der Abfragen deutlich, hat man einen Flaschenhals erfolgreich eliminiert.

    Nun, es wäre freilich zu schön, wenn es nicht doch den ein oder anderen Haken bei der Sache gibt; zum Glück lassen sich die meisten aber zumindest einigermassen elegant umschiffen.

    Eine Einschränkung von InnoDB ist beispielsweise, dass der FULLTEXT Index nicht unterstützt wird. Dies war bei My-Hammer ein Problem, weil wir eine Tabelle, die ziemlich eindeutiger Kandidat für eine Umstellung von MyISAM auf InnoDB war, in einem Teil unserer Applikation auch durchsuchen mussten, und zwar eben gerade einige TEXT-Felder, was ohne FULLTEXT Index nicht wirklich Spass macht.

    Die Lösung war, die Tabelle umzuwandeln und damit in der Tabelle selbst auf die FULLTEXT Indizes zu verzichten, per cronjob aber eine weitere Tabelle regelmässig mit den Daten der Ursprungstabelle zu füllen. Geschrieben wurde in diese Tabelle nur durch besagten Crobjobs, ansonsten fanden ausschliesslich Lesezugriffe statt, womit MyISAM wieder die perfekte Wahl war – und wir hatten unsere FULLTEXTs wieder. Schöner Nebeneffekt: durchsucht werden müssen eh nur eine Untermenge aller Zeilen der Ursprungstabelle, und es müssen auch nicht alle der (recht zahlreichen) Spalten in die Suchtabelle übertragen werden.

    Dadurch konnten wir nicht nur das Lockingproblem der ursprünglichen Tabelle lösen, sondern aufgrund der schlankeren Datenbasis in der Suchtabelle die Suche deutlich beschleunigen.

    Wichtig ist jedoch: diese Lösung ist nur möglich, weil wir in diesem Fall darauf verzichten können, auf absoluten Livedaten zu suchen.

    Meiner Erfahrung nach kann man zusammenfassend sagen: Es gibt nur eine einzige Massnahme, die mehr Performance bringt als Caching, und das ist noch mehr Caching. Das gilt, um mal zum Haupthema zurückzukehren, vor allem in Bezug auf Performance bei plötzlichen Besucheranstürmen.

    Statische Inhalte

    Wenn man einen TV Beitrag über die eigene Plattform überleben will, dann gibt es nichts, aber auch wirklich gar nichts Wichtigeres als dies hier: Die Startseite der Plattform ist eine statische HTML Seite. Und zwar in aller Konsequenz, was heissen soll, dass der Aufruf der Seite nicht nur keine Datenbankverbindung zur Folge hat, sondern dass noch nicht einmal der PHP Interpreter auch nur gestartet wird. Die Startseite von My-Hammer ist eine .html Seite, die im Gegensatz zu den .php Seiten per Apache-Konfiguration mod_php noch nicht mal von Weitem zu sehen bekommt. Selbiges sollte konsequenterweise auch für alle JavaScript und CSS Dateien, die von der Startseite eingebunden werden, gelten. Ob man hierfür nun mit Proxylösungen arbeitet oder Seiten regelmäßig vorgeneriert, ist Geschmackssache.

    Man darf nie den Performancevorteil reinen HTMLs unterschätzen – selbst wenn sich die Datenbanken schon alle verabschiedet haben und die Webserver bereits richtig unter Dampf sind: Eine HTML Seite auszuliefern schafft sogar ein Webserver, der schon ziemlich am Ende ist. Und man wahrt vor allem noch am ehesten sein Gesicht, wenn die ganzen neuen Benutzer, die aufgrund des TV Beitrages neugierig geworden sind, zumindest die Startseite zu sehen bekommen. Was immer man neben der Startseite noch an Seiten statisch vorgenerieren kann, ohne dass der angebotene Dienst selber “statisch” wird, sollte man natürlich machen (denn wie oft ändern sich schon Seiten wie Über uns?). Hierbei macht es Sinn, sich mithilfe der Zugriffsstatistiken einmal anzuschauen, welchen Weg neue Benutzer in der Regel auf der Plattform nehmen, um so auch wirklich jene Seiten zu cachen, die bei einem Ansturm am ehesten angesurft werden.

    Eine dynamische Seite als statische Seite vorzugenerieren ist dabei natürlich die konsequenteste Version von Caching, aber nicht immer praktikabel. My-Hammer nutzt eine zweite Stufe des Cachings, bei dem zwar weiterhin dynamische Seiten ausgeliefert werden, diese aber ganz oder teilweise in dedizierten Cache-Backends (wir nutzen dazu memcached) abgelegt sind, um Ergebnisse teurer Datenbankabfragen, die nicht immer absolut live zur Verfügung stehen müssen, zwischenzuspeichern. Diese zwischengespeicherten Einträge können zum einen nach einer gewissen Zeit ablaufen und werden dann neu aus der Datenbank erzeugt, oder können gezielt als “dirty” markiert werden, wenn die Datenbestände die sie widerspiegeln sich ändern.

    Wie oben erwähnt kann es sich außerordentlich lohnen, diese Cacheinhalte auf dedizierten Maschinen bereitzustellen – was wiederum deutlich zeigt, dass manche Massnahmen zur Performancesteigerung bestenfalls halbgar sind, wenn Admins und Programmierer nicht zusammenarbeiten.

    Everybody needs a 304

    (oder: Wie ich dem Browser des Users helfe, optimal zu cachen)

    Bisher bin ich lediglich auf ein Ziel von Performanceoptimierung eingegangen – zu verhindern, dass die eigenen Server zusammenbrechen, wenn’s mal brenzlig wird. Man muss sich aber unbedingt bewusst machen, dass Optimierungen auf dem Server erstmal keinen Wert an sich darstellen, sondern nur dem eigentlichen Ziel dienen: dem User die Benutzung der eigenen Seite so schnell und angenehm wie möglich zu machen – indem die Seite grundsätzlich erreichbar bleibt, und indem die Seite sich so schnell wie möglich aufbaut.

    Wenn man sich das erstmal bewusst gemacht hat, ist auch klar dass es sich sogar lohnen kann, etwas Rechenzeit auf dem Server zu investieren, um sie dem Client (also Browser) abzunehmen.

    Aber der Reihe nach. Es gibt ein wichtiges Hilfsmittel, um den Aufbau einer Webseite im Browser deutlich zu beschleunigen (abgesehen von den üblichen Massnahmen wie geringer Dateigröße, möglichst wenig eingebetteten Objekten etc.), und das ist die Verwendung des HTTP Status 304 Not Modified. Diesen kann der Server senden, wenn er anhand der Anfrage des Clients erkennt, dass exakt der Inhalt, den der Browser bereits in seinem Cache hat, nochmal über die Leitung wandern würde – in diesem Fall sendet der Server diesen Inhalt dann eben nicht nochmal, sondern teil dem Browser nur mit, er möge auf den Inhalt seines Caches zurückgreifen.

    Dies kann zu erheblichen Performancesteigerungen auf Seiten des Clients führen, denn die Zeit die zum Download des Inhalts einer Seite benötigt wird, entfällt.

    Es gibt nun zwei Faktoren, die das Status 304 Handling beeinflussen und spezielle Anpassungen erfordern, um optimales Clientcaching zu ermöglichen: Die Auslieferung von Seiten über PHP Skripte (gilt prinzipiell auch für andere Skriptsprachen) und der Betrieb einer Plattform in einem Webserver-Cluster.

    Zuerst zu letzterem: Um in der gegenseitigen Kommunikation festzustellen, ob ein Inhalt vom Server neu ausgeliefert werden muss oder der Browser den Inhalt aus dem eigenen Cache lädt, gibt es den sogenannten Etag. Ein ganz kurzer Abriss, wie die Verwendung abläuft. Der Client fragt eine Ressource beim Server an. Es ist der erste Zugriff innerhalb dieser Browsersitzung, deshalb schickt der Client kein Etag mit. Der Server sendet daraufhin die Inhalte aus, und schickt in den Headern den Etag des aktuellen Inhalts dieser Ressource mit, sagen wir “12345″ (der Server schickt dazu den Header Etag: “12345″).

    Fragt der Client nun erneut dieselbe Ressource beim Server an, schickt er in seinen Headern wiederum die Information mit, dass er in seinem Cache bereits die Inhalte mit dem ETag “12345″ gespeichert hat, und der Server ihn informieren möge falls sich die Inhalte nicht geändert haben (der Client schickt dazu den Header If-None-Match: “12345″). Der Server kann dann schauen, ob die Inhalte die er ausliefern würde immer noch das ETag “12345″ haben, und in diesem Fall den erwähnten HTTP Status 304 senden, oder, falls Inhalt und ETag nicht mehr zueinander passen, den neuen Inhalt schicken.

    Die Frage ist nun: Wie genau ist denn definiert, was im Etag steht? Nun, im Prinzip gar nicht. Es gibt kein vorgeschriebenes Format, wichtig ist nur die Definition des Etag an sich: dass nämlich ein eindeutiges Etag zu einem eindeutigen Inhalt einer bestimmten Ressource gehört, und deshalb festgestellt werden kann ob sich der Inhalt einer Ressource zwischen zwei Requests geändert hat oder nicht. Man kann sich den Etag deshalb der Einfachheit halber als Checksumme des Inhalts vorstellen (und in der Tat besteht eine Möglichkeit den Etag zu generieren darin, z.B. die MD5 Summe des Inhalts zu berechnen).

    Woher kommt der Etag? Beim Apache ist es Teil der Kernfunktionalität, für eine angeforderte Ressource den Etag zu berechnen und mitzusenden, sowie entsprechend zu reagieren wenn ein Client den If-None-Match Header sendet. Alles out-of-the-box also, aber genau hier liegen für uns die Probleme:

    Problem 1: Defaultmässig berechnet Apache den Etag für eine Ressource, indem eine Art Quersumme aus diesen Informationen generiert wird: I-Node-Nummer der angefragten Datei, letzter Änderungszeitpunkt (mtime) der angefragten Datei, und Größe der angefragten Datei. Betreibt man eine Webseite auf nur einem Server, hat man kein Problem, denn wenn z.B. die Datei /index.html zwischen zwei Aufrufen nicht verändert wird, hat sie bei beiden Zugriffen denselben Etag, da keiner der drei Faktoren inode, mtime, size zwischenzeitlich verändert wurde.

    Betreibt man aber einen Cluster aus mehreren Webservern, und besteht die Möglichkeit, dass ein Client bei zwei aufeinanderfolgenden Aufrufen derselben Ressource zuerst auf einem Webserver, beim zweiten Aufruf aber auf einem anderen landet, dann ist, auch wenn auf beiden Servern die exakt gleiche Datei liegt, der Etag beide Male ein anderer, denn selbst wenn letzter Änderungszeitpunkt und Größe der Datei auf beiden Servern identisch sind: dass die I-Node-Nummer die gleiche ist, ist praktisch ausgeschlossen. Der Server wird also keine 304 Status senden, obwohl er es könnte.

    Abhilfe ist zum Glück sehr einfach möglich, und lohnt sich schon beim Wechseln von einem auf zwei Server: Man muss dem Apache mitteilen, dass er die I-Node-Nummer nicht mehr zur Berechnung des Etag heranziehen soll. Dies erledigt an zentraler Stelle die Anweisung FileETag MTime Size. Mehr dazu im Apache Handbuch.

    Problem 2: mod_php hebelt die Verwendung von Etag für PHP Skripte aus. Das macht ja prinzipiell auch Sinn: selbst wenn die Skriptdatei /index.php sich zwischen zwei Aufrufen inhaltlich überhaupt nicht geändert hat, kann sie dennoch völlig unterschiedliche Inhalte an den Client ausliefern – genau das ist ja Sinn und Zweck des Einsatzes von dynamischen Seiten.

    Trotzdem kann es Sinn machen, dass der Server den Status 304 an einen Client sendet, wenn dieser dieselbe Ressource erneut anfragt. Zum Beispiel bei CSS Skripten, die von jeder Seite der Plattform eingebunden werden, und aus programmiertechnischen Erwägungen als PHP Skripte realisiert sind, aber deren Inhalt sich trotzdem sehr selten ändert. Jeder Seitenaufruf würde den Browser veranlassen, dies referenzierte CSS Datei anzufragen, und der Server würde jedes Mal den Inhalt senden, obwohl sich dieser seit dem letzten Aufruf nicht geändert hat. Das macht den Seitenaufbau im Client langsam, und ist zudem eine Ressourcenverschwendung.

    Wie kann man nun sicherstellen, dass ein Client den 304 Status auch beim Abruf von PHP Skripten erhält, falls sich der Inhalt nicht verändert hat, aber auch auf keinen Fall einen 304 Status bekommt, falls der Inhalt sich geändert hat? Die Lösung ist leider nicht ganz so trivial wie beim ersten Problem, aber doch vergleichsweise einfach zu realisieren.

    Da wie erwähnt der Zustand der Skriptdatei selbst praktisch keine Rolle spielt, darf man nur mit dem von diesem Skript auszuliefernden Inhalt arbeiten. Eine Lösung wäre, bei den Skripten, für die man den Etag Mechanismus einsetzen möchte, folgenden Code ans Ende anzuhängen (lässt sich natürlich einfach in eine zentrale Funktion kapseln): <?php $output = ob_get_clean(); // Gesamte Ausgabe, die an den Client gesendet werden soll, abfangen und zwischenspeichern $etag = ‘”‘.sha1($output).’”‘; // Prüfsumme der Ausgabe berechnen// Ist der Inhalt identisch mit dem, den der Client gecached hat? if ($_SERVER['HTTP_IF_NONE_MATCH'] == $etag) // Wenn ja, dann sende nur den Status 304 { header(‘HTTP/1.x 304 Not Modified’); header(‘Etag: ‘.$etag); die(); } else // Wenn nicht, dann sende den Inhalt inkl. des neuen Etags { header(‘Etag: ‘.$etag); echo $output; die(); } ?>

    Voraussetzung ist dafür die Verwendung von output buffering.

    Eines muss man ganz klar festhalten – für den Server fällt exakt dieselbe Arbeit an, egal ob der User den Inhalt schlussendlich zugesendet bekommt oder nur die lapidare Meldung, er möge doch auf seinen Cache zurückgreifen. Es mag nach deutlich zuviel Overhead aussehen, PHP soviel Arbeit erledigen zu lassen, nur um das Ergebnis dieser Arbeit dann wegzuschmeissen; aber der Effekt auf die Lade- und damit Seitenaufbauzeiten beim Client ist wirklich beeindruckend, wenn man diesen Mechanismus geschickt einsetzt.

    ]]>
    /2007/07/17/recycelter-artikel-my-hammer-das-fernsehen-und-die-serverlast/feed/ 0