About May 2008

This page contains all entries posted to /blog/wvk in May 2008. They are listed from oldest to newest.

April 2008 is the previous archive.

September 2008 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.31

« April 2008 | Main | September 2008 »

May 2008 Archives

May 5, 2008

Das "Geheimnis" von deklarativen Assoziationsdefinitionen

Da ich nunmehr in zwei verschiedenen Sprachen mich mit dem Thema der deklarativen Art der Definition von Assoziationen zwischen Klassen beschäftige, schien es mir sinnvoll, darüber an dieser Stelle mal etwas zu schreiben.

Erstmal: was meine ich mit diesem toll klingenden Konzept überhaupt? Ich meine damit das, was jeder Rails-Mensch kennt:

class Foo < ActiveRecord::Base
  has_many :bars
  belongs_to :baz
end

oder, mit dem in meinem letzten Post beschriebenen JS-Framewörkchen:

var Foo = ActiveResource.inherit({
  has_many: {
    bars: {}
  }
  has_one: {
    baz: {}
  }
});

Was man erwartet, ist dass ein Aufruf von foo.bars() die Liste aller zu foo gehörenden Bar-Instanzen liefert. Das zu bewerkstelligen ist in jeder Scriptsprache, die so etwas wie eine eval()-Methode oder gar ein ausgefeiltes Mataprogrammier-Konzept wie Ruby kennt, an sich relativ einfach. Das Rezept (am Beispiel von has_many):

  • man definiere eine Methode, welche die find-Methode der assoziierten Klasse mit einem Kontext definierenden Argument wie "für foo_id=self.id" auf. Ich schreibe das bewusst so allgemein, weil die konkrete Implementierung stark von der zu Grunde liegenden Persistenz abhängt -- es könnte (im Falle von ActiveResource) die Generierung einer URL mitsamt eines HTTP-Requests, oder (im Falle von ActiveRecord) die Generierung einer SQL-Query oder einer Suche-in-Textdatei-Methode oder oder... sein.
  • man definiere eine Klassenmethode namens has_many, die als Argument mindestens den Namen der Assoziation entgegennimmt (und daraus ggf. den Klassennamen der assoziierten Klasse herleitet)
  • man generiere eine Methode mit dem Namen des an has_many übergebenen Arguments (z.B. foos), die die erstgenannte Methode kapselt. In Javascript kann man z.B. mit sowas wie eval('Foo.prototype.' + association_name + '=function(){....}') arbeiten. In Ruby würde man die Methode eher gleich mittels define_method dynamisch generieren (define_method association_name do ... end).
  • man freue sich, dass bei einem Aufruf von foo.bars() nun das gleiche zurückgegeben wird, wie es (im Falle von RoR) bei Bar.find(:all, :conditions => "foo_id=#{foo.id}") der Fall wäre.

Aaaaber: das kann doch noch nicht der ganze Zauber gewesen sein? Und in der Tat, das ist erst ein kleiner, naiver Anfang. Wer Rails genauer kennt, weiß dass auch Konstrukte wie foo.bars.find_by_name_and_trallalla() ohne weiteres möglich sind. Dabei ist diese find_by...-Methode nicht etwa eine Methode der zurückgegebenen Collection (ich nenne das mal so, weil es je nach Sprache ein Array, ein Hash oder sonst eine iterierbare Objektsammlung sein kann), sondern wenn dann eine Klassenmethode von (in diesem Falle) Bar. In A Nutshell: Was auch immer beim Aufruf von foo.bars() zurückgegeben wird, es implementiert sowohl die Schnittstelle einer Collection (Array,...) als auch der Klasse, zu der die erwarteten Objektinstanzen gehören. (Genau genommen stimmt das nicht 100%ig, aber an dieser Stelle reicht diese Annahme).

Der geneigte Leser möge sich einstweilen den Rails-Code zu Gemüte führen und dabei feststellen, dass foo.bars() ein "Association Proxy"-Objekt zurückliefert. Dieses Objekt beinhaltet sämtliche Informationen darüber, wie die beiden Klassen zueinander in Beziehung stehen, wie die Instanzen der assoziierten Klasse geholt werden können und stellt Methoden bereit, um auf diese wie in einem Array zuzugreifen. Etwas genauer gesprochen erstellt die has_many-Methode ein Objekt, in dem die Informationen zu der Assoziation zwischen den Klassen gehalten wird und beim Aufruf der entsprechenden Objektmethode (foo.bars()) wird ein Objekt mit Informationen zu den Instanzen der referenzierten Klasse erstellt und zurückgegeben.

Mit dieser Information im Hinterkopf und etwas Geschicklichkeit ist es relativ einfach, miteinander in Beziehung stehende Resourcen jeder Art umzusetzen. Die Details wie man innerhalb des einen Objektes an das jeweils andere Objekt heran kommt, können hinter einer einheitlichen Schnittstelle (die des "Association Proxies") gekapselt werden. Somit ist es dann auch wenig umständlich, z.B. in RoR ActiveRecord- und ActiveResource-Objekte miteinander zu verknüpfen, über die gleiche deklarative Syntax wie man ActiveRecord-Objekte untereinander verknüpft. Ich arbeite gerade noch an einer halbwegs vollständigen, jedenfalls aber brauchbaren Implementierung dafür, denn ich sehe nun schon bald eine Handvoll Projekten, wo das zumindest Hilfreich wäre (Stichwort: Anwendung mit Benutzerverwaltung in einer anderen Anwendung, Kommunikation über HTTP/XML). Sobald das veröffentlichungswürdig ist, wird es selbstverständlich hier erscheinen.

May 15, 2008

Daten vernichten: wenn, dann richtig!

Wie es sicht gehört, hatte die Festplatte meines alten Notebooks eine halbe Woche vor Ankunft des neuen ihren Geist aufgegeben. Glücklicherweise konnte ich die wichtigen Partitionen vollständig retten.

Vorgestern abend wollte ich dann doch noch einmal versuchen, durch anlegen einer neuen Partition und vorherigem Bad-Block-suchen die Platte doch noch als externes Laufwerk brauchbar zu machen. Erste Aktion ist bei sowas dann immer ein shred /dev/sdb. Als Shred nach 24 Stunden immer noch nicht fertig war, die Platte 25mal mit Zufallszahlen zu überschreiben, brach ich eben ab und legte eine neue Partition mit Ext3 an. Als erstes folgte sodann ein fsck.ext3 -cc -C 0 -f -p /dev/sdb1, was aber nach 10 Stunden Lauf noch immer nicht die mit -C 0 angeforderte Fortschrittsanzeige hergab. Ein Blick auf die Systemkonsole ergab dafür ein im Klack-Rhythmus der Platte ausgegebenes "reset high speed USB device using ehci_hcd and address 6". Mit anderen Worten: nicht nur die kaputten Sektoren waren ein Problem.

Wie entsorgt man also eine Platte? Shred schien auf Grund eines Hardwaredefektes nicht weiter zu kommen. Also musste die Datenhaltige Schicht der Platte auf anderem Wege zerstört werden. Aufschrauben und zerkratzen? Das wäre zu viel arbeit gewesen und hätte immer noch zu große Bereiche lesbar gelassen. Platten ausbauen und in die Mikrowelle legen? Was bei CDs sehr effektiv ist, möchte ich mit einer Festpatte lieber nicht probieren. Die ganze Platte einfach Schwefelsäure eintauchen? Leider nicht zur Hand.

Letzten Endes bliebt dann nur noch eines: der Hammer. Erstaunlicherweise ist dieses Instrument äußerst effektiv, denn die Platte besteht nicht wie bei Desktop-Platten aus Aluminium, sondern aus Glas. Also ein kräftiger Schlag und die Daten sind sicher :) -- Natürlich sollte man dann dennoch das Gehäuse aufschrauben um die Splitter über diverse Mülleimer zu verteilen, denn so lange die gesammelt in dem Gehäuse liegen, ist das für eventuelle Datenschschnüffler nichts weiter als ein tolles 1001-teiliges Puzzle :)