About December 2007

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

November 2007 is the previous archive.

January 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

« November 2007 | Main | January 2008 »

December 2007 Archives

December 7, 2007

Ein Desktop für den Admin

Bei der Suche nach einer vernünftigen Startseite für den Ober-Admin meiner Applikation bin ich nun etwas weiter gekommen. Noch bin ich weit weg von einem einheutlichen und einleuchtenden "Workflow", aber eigentlich liegt das Haupt-Augenmerk der Diplomarbeit ja auch auf der Kern-Infrastruktur (OK, da gehört eigentlich aucht die Oberflächen-Infrastruktur zu, denke ich...). Jedenfalls fragte ich mich:

  • Was muss ein Admin (also ich ;-)) auf seriner Einstiegseite sehen?
    • eine Übersicht über die häufigsten Aktionen (Kunden anlegen, FTP-&Emailkonten anlegen, ...)
    • eine Übersicht über die Systemauslastung/Resourcenverbrauch
    • eine Liste mit anstehenden Aufgaben (Kundenanfragen, Systempflege,... -- NICHT Teil deser Arbeit!)
    • bestimmt noch mehr... also was noch?

  • Was muss ich NICHT auf der Startseite sehen?

    • Gute Frage!

Da sicher jeder Admin andere Vorlieben hat, habe ich ein kleines Experiment angefangen, was bislang ganz gut läuft: Es gibt jetzt einen Admin-Desktop mit Icons die zu den o.g. Aufgaben verlinkt sind. Außerdem gibt es eine beliebig einstellbare Anzahl sog. "Applet-Felder", auf die man die (meisten) Icons draggen&droppen kann, um sie als "Applet" darzustellen:

snap28.png

Beispielsweise kann man in einem Feld den Speicherverbrauch im Auge behalten, während man in einem anderen Feld einen Kunden anlegt (alles schön per Ajax). Oder, plausibler, ich lege einen Kunden an, währenddessen ruft ein anderer Kunde an der gerne sein Kennwort neu gesetzt haben will -- statt nun ein neues Browserfenster zu öffnen, kann ich also "Kennwort ändern" auf ein freies Applet-Feld ziehen und die Aufgabe dort erledigen ohne die andere aus dem Auge zu verlieren...

snap29.png

Ein weiterer kleiner Vorteil ist, dass man seine Startseite nun relativ frei einteilen kann. Und ja, natürlich werden die "Applets" gespeichert, d.h. wenn man die seite verlässt und später wieder aufruft, erscheinen alle Applets wieder an der Stelle wo man sie vorher hingepackt hat (momentan ist das noch an die Session gebunden, das kann man aber genausogut persistent in die Datenbank auslagern).

Natürlich kann man auch einfach die Icons anklicken um zu einer nicht-AJAX-Basierten Version der Aktionen zu kommen.

Bäume und Navigation

Ich hatte mir neulich überlegt, für gewisse Aufgaben in meiner Applikation eine Baum-Navigation zu bauen. Philipp hatte dereinst die Idee geäußert, alle Kunden als hauptknoten darzustellen, dann darunter aufklappbar deren bezogenen Leistungen wie HTTP-Hosts, FTP- und Email-Konten und darunter deren Details... An sich eigentlich eine ganz gute Idee, so dachte ich mir, aber ziemlich aufwändig in der Umsetzung. Und als ich dann dieser Tage mich an die Umsetzung wagen wollte, da bin ich auf einen sehr überzeugenden Artikel gestoßen: Why is a tree view a poor navigational choice in software applications?. Diese Liste schien mir recht überzeugend. Der nächste Artikel befasst sich darum auch mit Alternativen: Tree View Removal Surgery. Sehr toll.

Ansonsten gilt zu sagen: Ich würde mich gerne mal mit einem Usability-/UI-Spezialisten unterhalten, denn ich merke dass ich von gutem Oberflächendesign nicht besonders viel Ahnung habe...

December 8, 2007

Produktives Coden

Was außer dem was ich neulich schon einmal gepostet habe ist dem produktiven Coden zuträglich? Ein paar weitere Kleinigkeiten:

  • Die Gewissheit, dass einem keiner Mails schreibt (Mailprogramm zumachen reicht nicht!). Für Telefonate gilt das gleiche.
  • Raumtemperatur über 19°C (bei 18° sind meine Finger definitiv zu steif zum schnellen Tippen)
  • eine große Kanne Tee (oder Kaffee...), bevorzugt mit irgend einer Warmhaltevorrichtung (wenn man nach zwei Stunden feststellt, dass das Getränk kalt ist, reißt einen das schnell aus dem Flow...)
  • Irgendwelcher Knabberkram (Schokolade und Gummibärchen) in der obersten Schublade hilft über Denkpausen hinweg und sorgt für konstanten Zuckernachschub
  • die passende Musik -- leider kann ich noch nicht sagen, welche Musik zu welcher Zeit mit welcher Art von Problemstellung am besten funktioniert. Ich weiß nur, dass Pianokonzerte das Tippen sehr gut begleiten. Aber Metal oder Electronic sind auch oft gute Begleiter. "Einfache" Popmusik, Blues oder Techno hingegen eher nicht. Sicher ist das vom persönlichen Musikgeschmack abhängig -- vielleicht komplizierte Musik bei komplizierten Problemen?
  • Was mir beim Programmieren von Ruby auffällt ist, dass es sich schneller programmieren lässt als viele andere Sprachen, die mehr "Interpunktion" aufweisen: Dadurch, dass man im Wesentlichen ganze Wörter und nicht kryptisch abgekürzte Namen und Sonderzeichen eintippen muss, empfinde ich das "Tipp-Erlebnis" als fließender -- fast wie beim Schreiben eines normalen Textes.

Die restlichen, üblichen Ergonomieempfehlungen kann man jedem entsprechenden Standardwerk entnehmen, denke ich. Diese Punkte waren mir nur persönlich für mich aufgefallen...

Transaktionen braucht Consolvix

Ein sehr guter Punkt, auf den mich Phillip gestern Abend hingewisen war, ist nun umgesetzt: Das Anlegen von neuen Kunden/Hostingaccounts ist nun in Transaktionen gekapselt, die voneinander vollkommen unabhängig sind. Gleichzeitig habe ich die Speicherung der temporären Transaktionsdaten aus der session-Variable herausgeholt und als normale AR-Entität in die Datenbank ausgelagert. Das geschah mit dem Hintergedanken, dass so eine Transaktion ja universell sein soll und es durchaus vorkommen könnte, dass man mal Arbeit anfängt und sich dann für die Mittagspause ausloggt. Oder eine Transaktion könnte Schritte enthalten, die von verschiedenen Benutzern ausgeführt werden müssen, z.B. die Bestätigung eines neuen Kennworts: Der Admin startet die Transaktion, eine Mail wird an den Kunden verschickt, dieser bestätigt sein neues Kennwort und damit ist die Transaktion erst abgeschlossen.

Nun wo also Arbeit über mehrere Sitzungen verteilt werden kann, macht es Sinn, die angefangenen Transaktionen gleich auf der Admin-Startseite anzeigen zu lassen. Dazu gibt's jetzt also ein neues Applet was genau dieses tut:

Diese Liste umfasst einen Link zu den jeweils offenen Transaktionen. Dazu wird pro Transaktion gespeichert, welcher Controller und welche Aktion aufgerufen werden muss, um die Arbeit weiterzuführen. Außerdem werden die Zeiten gespeichert, an denen die Transaktion gestartet bzw. bearbeitet wurde und von wem. Summa summarum schaut die Entity also so aus:

consolvix_transactions(id, number, user_id, controller, action, description, data, created_at, updated_at)

Das data-Feld enthält die als YAML serialisierten "Sitzungs"-Daten.

Als API-Funktionen stehen jedem Controller nun start_transaction, transaction_started?, cleanup_transaction', 'load_transaction sowie save_transaction zur Verfügung.:

  • start_transaction(description, action, controller=nil) erstellt ein neues Transaktionsobjekt mit den angegebenen Daten.
  • load_transaction lädt, sofern als Parameter eine gültige TID angegeben wurde, die Daten aus der Datenbank nach @transaction, welches danach dem Controller/den Views zur Verfügung steht.
  • transaction_started? prüft nur, ob dieses Objekt NIL ist oder nicht.
  • load_transaction sollte als before_filter aller Aktionen eingesetzt werden, die auf die transaktionen zugreifen möchten. Eingebunden wird der Filter über use_transaction_for :aktion1, :aktion2, ...
  • save_transaction kommt entsprechend als after_filter an die Aktionen, die die Daten möglicherweise verändert haben könnten. Dies kann über save_transaction_for :aktion1, :action2, ... bewerkstelligt werden.

Am Beispiel "Anlegen eines Hosting-Accounts" passiert nun Folgendes: wird create_hosting_account aufgerufen, so wird eine neue Transaktion gestartet (sofern nicht als parameter bereits eine gültige TID übergeben wurde) und nach cha_do_create/1 weitergeleitet. Wird cha_do_create/[schritt-nummer] ohne gültige TID aufgerufen, wird erst geschaut, ob offene Transaktionen (für den aktuell eingeloggten Benutzer) vorhanden sind. Wenn nicht, wird nach create_hosting_account umgeleitet. Wenn eine Transaktion vorhanden ist, wird diese fortgeführt. Wenn mehrere Transaktionen offen sind, wird nach cha_select_transaction umgeleitet, wo der Benutzer die gewünschte Transaktion auswählt und schließlich wieder nach cha_do_create umgeleitet wird. Jederzeit kann abort_create aufgerufen werden, was die Transaktion beendet und löscht.

Ich werde jetzt mal sehen inwieweit es Sinn macht, alle "erstellen"- und "bearbeiten"-Dialoge in Transaktionen zu verpacken. Ich denke aber, dass es nur bei Aktionen mit mehr als einer Eingabemaske Sinn macht, da die zu speichernden Daten mindestens einmal gePOSTet werden müssen. Aber man könnte natürlich genausogut bei ein-formularigen Aktionen einen "Zwischenspeichern"-Button einbauen. Was sagen die Usability- und anderen Experten dazu?

December 9, 2007

Böser Bug in Rails 1.2.6

Das Serialisieren von Sitzungs-/Transaktionsobjekten zur Speicherung in der Datenbank mittels YAML ist in Rails eigentlich super-einfach:

class ConsolvixTransaction < ActiveRecord::Base
  serialize :data, Hash
  # ...

  def [](key)
    self.data[key]
  end

  def []=(key, value)
    self.data[key] = value
  end
end

Obiger Code veranlasst Rails, die data-Spalte vor dem Speichern zu serialisieren und nach dem laden wieder zu deserialisieren. Dann kann ich während eine Transaktion aktiv ist einfach über

@transaction[:address] = Address.new(params[:address])

z.B. ein neues Adressenobjekt in der Transaktion ablegen und theoretisch später wieder darauf zugreifen. Aber weit gefehlt, denn Rails deserialisiert das Objekt nachher nicht als Address-Objekt, sondern als YAMLObject.

Eine kurze Internetrecherche ergab, dass das tatsächlich ein Bug in Rails ist: http://dev.rubyonrails.org/ticket/7537 bzw. http://dev.rubyonrails.org/ticket/8933

Die bei Ticket Nr. 7537 vorgeschlagene Lösung, den folgenden Code in die environment.rb einzufügen, funktioniert zwar so weit, aber dass ich nun für jede theoretisch mögliche Entität, die einmal in einer Transaktion vorkommen könnte, ein require hinzufügen muss, ist mehr als nur hässlich.

require 'address'
require 'client'
require 'domain'
require 'email_address'
require 'system_user'
require 'user'
require 'email_account'
require 'ftp_account'
require 'hosting_account'

YAML.add_domain_type("ActiveRecord,2007", "") do |type, val|
  klass = type.split(':').last.constantize
  YAML.object_maker(klass, val)
end

class ActiveRecord::Base
  def to_yaml_type
    "!ActiveRecord,2007/#{self.class}"
  end
end

Kennt jemand anderes von euch dieses Problem auch? Existiert das noch in Rails 2.0 oder einer späteren Version als 1.2.6?

December 13, 2007

Rails Helper v0.3

Server Tab
Server starten/stoppen
Migration Fix
rake db:migrate VERSION=... geht nun
Stats Button
Button für Code-Statistik

Es hat sich wieder etwas getan um das numehr zum dritten Male hochgelobte Rails-Helper-Applikatiönchen, welches soeben in seiner 0.3. Version erschienen ist.

Erweiterungen

  • ein neues Tab zur Kontrolle des Webrick-Servers ist hinzugekommen. Zur Zeit kann man damit den Server nun nur starten oder stoppen. Eigetnlich soltle man das auch von Kdevelop aus bewerkstelligen können, aber das stoppend es Servers klappt dir nicht so wie vorgesehen -- daher diese eigene Implementierung.
  • im Tab "Rake" ist zum Leidwesen derer, die nichts von LOCs halten ( ;-)), ein weiterer Button zur Anzeige von Code-Statistiken (rake stats) hinzugekommen.
  • Die Terminalausgaben assen sich nun auf Knopfdruck löschen (noch nicht in den Screenshots abgebildet)

Bugfixes:

  • das Auswählen einer Migrations-Version != 0 funktioniert jetzt auch tatsächlich (hatte vorher einen Syntaxfehler wegen "+" vor der Versionsnummer gegeben) (Beweis siehe Screenie ;-))
  • die Schriftart in den Termninals wurde auf Monospace gesetzt, um die Ausgaben etwas Leserlicher zu gestalten.

Herunterladen kann man sich die neue Verson hier: Download Rails Helper v0.3. Zur Erinnerung, ausführen kann man das Script nur mit dem Kommander-Executor.

Transaktionen die Zweite

Hurra, es ist vollbracht! Nach zwei Tagen des frustgeladenen Programmierens bis in die späten Morgenstunden hinein scheint meine Transaktions-API nun relativ solide geworden zu sein. Es haben sich einige Änderungen gegenüber dem ergeben, was ich bereits in meinem letzten Eintrag zu dem Thema schrieb. Doch alles der Reihe nach:

  • Der gesamte Transaktionsrelevante Code liegt jetzt in einem eigenen Modul: Consolvix::TransactionAPI. Wenn also nun ein Controller für gewisse Aktionen Transaktionsfunktionalität braucht, kann er diese über include Consolvix::TransactionAPI einbinden.
  • Um einen aus mehreren Schritten aufgebauten Transaktionshandler zu erstellen, dient die methode transaction_handler. Diese generiert aus den angegebenen Daten alle Unterschritte und Überpfügungsmethoden als Stubs.
  • das Laden und Speichern der aktuellen Transaktion geschieht automagisch über in transaction_handler eingefügte before- bzw. afterfilter (Danke an Daniel für die Zeit die du dir genommen hast, nach dem Gepräch hat's irgendwie funktioniert -- darüber reden hilft oft schon g)
  • um die korrekte Weiterleitung an die richtigen actions kümmert sich der beim Aufruf von transaction_handler generierte Code ebenfalls vollständig selbst, im Wesentlichen immer noch so wie im letzten Eintrag beschrieben. Nur eben schön versteckt für den Programmierer. Die Einzige wichtige Änderung, die sich ergeben hat, ist dass die Schrittnummer jetzt als parameter und nicht mehr als ID-Teil der URI mitgegeben wird -- aus dem Grunde, weil z.B. eine "bearbeite Kunde soundsoviel" eine ID-Angabe benötigt...

Nehmen wir nun also an, im HostingAccountsController sollen die beiden Aktionen new und edit als mehrschrittige Transaktion ausgeführt werden. Dazu definiere man dann zuerst das Folgende:

class HostingAccountsController < ApplicationController
  transaction_handler 'Edit Hosting Account',
                      :edit,
                      :worker   => :update,
                      :selector => :select_update_transaction
                      1 => [:edit_step1, nil],
                      2 => [:edit_step2, :step1_done?],
                      3 => [:edit_step3, :step2_done?],
                      4 => [:edit_save,  :step4_done?]

  transaction_handler 'Create Hosting Account for existing Client',
                      :new,
                      :worker => :create,
                      1 => [:cha_step1, nil],
                      2 => [:cha_step2, :step1_done?],
                      3 => [:cha_step3, :step2_done?],
                      4 => [:cha_save,  :step4_done?]

end

Die Argumente bedeuten folgendes:

  • Menschenlesbare Beschreibung, die z.B: beim Auswählen unfertiger Transaktionen angezeigt wird.
  • Name der Haupt-Aktion = "Name der Transaktion", im folgenden main_action genannt. Diese erstellt eine neue Transaktion und leitet anschließend an die worker_action weiter.
    • :worker (optional, default = "do#{mainaction}"): die Aktion, an die im späteren Verlauf jeweils alle Daten gesendet werden, unter Angabe des aktuellen Schrittes.
    • :selector (optional, default = "selecttransact#{main_action}"): die Aktion, die aufgerufen wird wenn keine (gültige) Transaktions-ID an die worker_action übergeben wurde UND wenn mehrere Transaktionen des verlangten Typs offen sind.

  • 1...n => [action, prerequisite]: dieser hash hat als Schlüsel die Schritt-Nummer und als Wert den Namen des auszuführenden Unterschrittes sowie seine Vorbedingung, die erfüllt sein soll. Die hier angegebenen tatsächlichen Unterschritte der Transaktion sind protected und nicht direkt aufrufbar. Der Zugriff wird über die worker_action geregelt, die bei jedem Aufruf prüft, ob zur Aufgerufenen Schritt-Nummer auch die Vorbedingung erfüllt ist. Vorbedingungen sind Methoden, die einen boolean-Wert zurück geben. Wenn sie nicht in der Controller-Klasse explizit implementiert werden, dan werden die vordefinierten Stubs aufgerufen, die immer FALSE liefern -- so merkt man als Entwickler schnell mal, dass man was vergessen hat zu implementieren ;-)

Für die ganz harten unter der werten Leserschaft dieses Blogs hänge ich gleich mal den Code von TransactionAPI an. Wer die Muße hat, ihn durchzulesen und zu verstehen (müsste machbar sein, er ist sogar kommentiert ;-)) und mir dazu Ideen und Verbesserungsvorschläge oder einfach nur fiese Detailfragen zu stellen, der sei an dieser Stelle herzlich dazu eingeladen.

December 19, 2007

Faktensammelsurium

Der heutige Tag hatte es mal wieder in sich. Erst eine mühselige Reise aus .nl (familiäre Gründe...) zurück, die doppelt so lange dauerte als eigentlich nötig gewesen wäre, dann die Feststellung dass ich abgesehen von der Diplomarbeit auch noch andere Arbeitsberge zu bewältigen habe, dann ein Bug der sich einfach nicht lokalisieren geschweige denn beheben ließ, und dann noch ein durch ein fehlgeschlagendes glibc-Update unbrauchbar gewordenes Betriebssystem auf meinem Hostingserver. Während nun also das 4 Stunden alte Backup über die DSL-Leitung gequetscht wird, kann ich mir ja ein paar Minuten des Zusammenfassens meines Arbeitsfortschrittes widmen.

Erste Feststellung: Ich hatte gehofft, die während der letzten beiden Tage weiter zu kommen -- weiter, als ich jetzt gekommen bin. Aber das ist ja eh immer dasselbe...

Zweite Feststellung: Nach einem Gespräch mit Prof. Klingspor letzte Woche habe ich nun eine relativ kontrastreiche, wenn auch noch etwas unfokussierte Vorstellung davon, wie ich meine Arbeit strukturieren werde und was nicht reinkommen wird.

Dritte Feststellung: Ich werde voraussichtlich in drei Wochen so weit sein, dass ich nur noch an der Arbeit schreiben muss. Natürlich funktioniert noch nicht alles so wie es funktionieren soll, aber ich behaupte, die wichtigsten Aspekte der "Kern-Infrastruktur" mittlerweile berücksichtigt zu haben -- mindestens theoretisch, und eine Diplomarbeit ist nunmal auch eine Menge Theorie. Vom Umfang des produzierten Codes her bin ich schon lange weit genug, eigentlich.

Ich hoffe, in einem Monat eine Consolvix-Version zu haben, die sich zumindest für den Admin rudimentär produktiv einsetzen lässt -- und das gleich auf einem niegelnagelneuen Server, den zu bauen es allerdings auch noch gilt...

Doch nun geht's weiter mit dem Wiederherstellen des o.g. Servers, rsync hat seinen Job offensichtlich getan.

NACHTRAG: Lang lebe rsync, der Server geht wieder. Der rest bleibt beim alten.

December 31, 2007

Nichts Weltbewegendes...

Ein Jahr neigt sich dem Ende entgegen,
ein weiteres lässt nicht lange warten,
eine neue Chance, die Welt zu bewegen,
auf neue, noch nicht erprobte Arten ;-)

Allen Lesern dieser Zeile wünsche ich ein angenehmes Jahr 0x7D8, Gesundheit, Freude am Dasein, und dass ihr im neuen Jahr all das schafft, was ihr letztes Jahr nicht geschafft habt -- und noch ein Wenig mehr :)

Möge der Code mit euch sein!

neujahreskarte.png