Blog

  • Aufwandschätzungen sind doch kein Zufall

    Letzte Woche hat mich ein Arbeitskollege gefragt, ob ich kurz ein kleines Teilprojekt schätzen könnte. Hintergrund: Der Kunde wollte ein paar funktionale Erweiterungen für die bestehende Webseite. Mein Arbeitskollege hatte bereits eine Aufwandschätzung gemacht, welche jedoch aus Kundensicht viel zu hoch schien. Also bat er mich, auch einen Blick darauf zu werfen.

    Ich kannte das Projekt ein wenig aus der Entwicklungsphase, da ich dort in einigen konzeptionellen Fragen involviert war. Ich hatte jedoch absolut keine Ahnung von den neuen Kundenwünsche und schon gar nicht, was mein Arbeitskollege geschätzt hat.

    So machte ich mich an die Arbeit, ich hatte eine Liste mit ca. 10 Punkten aus der Offerte. Ich ging die Liste Punkt für Punkt durch und mir die folgenden Fragen:

    • Wie lässt sich der Punkt umsetzen?
    • Sind externe System mit involviert?
    • Ist Entwicklung notwendig oder lässt sich alles mit bestehenden Modulen umsetzen?
    • Gibt es Risiken bzw. Dinge, welche unklar sind?

    Je nach dem, wie die Antwort auf die Frage war, wurde der Aufwand ein wenig höher, bzw. ein wenig tiefer. 10x wiederholte ich das Spiel.

    Resultat: ca. 20 Personentage Aufwand. Ehrlich gesagt, ich war nervös bzw. aufgeregt, als ich ins Büro nebenan ging. Wieviel würde er wohl geschätzt haben?!

    Auch er hat die Punkte, welche offeriert wurden, einzeln geschätzt. So konnten wir diese Schrittweise durchgehen. Erstaunlich: In den ersten 4 Punkten 100% Übereinstimmung. Es gab 2-3 Punkte, wo es eine ganze kleine Abweichung gab, aber alles in allem doch ein extrem grosse Übereinstimmung.

    Fazit: Aufwandschätzungen sind also doch nicht nur Zufall! Besonders das Aufteilen in kleinere Teilaufgaben war extrem hilfreich. Wenn man dann noch ein bisschen was fürs Projektmanagement hinzufügt, sowie eine gesunde Reserve ist man sicher auf der richtigen Spur.

    Problem ist dann halt meistens nur, dass das Marketing den Preis drückt, um Konkurrenzfähig zu bleiben… danach fragt man sich, warum es mit dem Budget nicht aufgegangen ist… aber das ist dann nicht mehr ein Entwicklerproblem.

    Besonders für Drupalprojekte habe ich die Erfahrung gemacht, dass es einige Punkte gibt, welche den Aufwand fast ausnahmslos steigen lassen:

    • Migration von bestehendem Inhalt. Wird immer unterschätzt, da von einer idealisierten Umwelt ausgegangen wird. In der Realität sind oftmals die Daten schlecht, müssen noch umgewandelt werden usw.
    • Jegliche Interaktion mit unbekannten Drittsystemen. Auch wenn es noch so trivial ausschauen mag… irgend eine Tücke ist noch drin.
    • Mehrsprachigkeit. In Drupal grundsätzlich kein Problem, aber im Detail, gibt es immer wieder ein Modul, welches (noch) nicht mehrsprachig ist oder irgendwo Zeichenketten, welche sich nicht übersetzen lassen.

    Dies sind besonders in der Medienbranche immer wieder auftauchende Anforderungen und oftmals auch immer wieder Risikotreiber.

  • Fast Gallery – Quickstart

    Checkout the Fast Gallery overview page.

    This is a quick start for setting up a Fast Gallery. I did this with Fast Gallery 5.5 and Drupal 6.17.

    First a quick introduction on how Fast Gallery works. Basically Fast Gallery displays a pictures from a folder, just like you know it from Windows Explorer. So lets say you uploaded 50 pictures to your site via FTP, you point your gallery to the folder, then user is presented those 50 pictures. If there are subfolders, the user can just click on the folder and will see the pictures from this subfolder (just like in Windows Explorer).

    1. Copy the latest version of Fast Gallery into your modules folder
    2. Install Fast Gallery
    3. Install Imagecache and setup two presets: "thumbs" and "full" (for example)
    4. Go to admin/settings/fast_gallery/general. Here we are going to setup a gallery
    5. On the top we got three text fields: "Path to Gallery", "Path Alias" and "Title of Gallery". Path to gallery would the folder where the images are located relative to the Drupal index.php, so for example sites/default/files/galerie. Path Alias, would be any alias, so for example: my_gallery, and the "Title fo Gallery" could be something like "My first Fast Gallery"
    6. There are two dropdowns for selecting imagecache presets. Since you created two imagecache presets previously you can select them now here
    7. On the same page we we have other options, which we can leave as they are
    8. Hit the submit button
    9. That's it, you are done! Go to http://mysite.com/my_gallery and you should see some images

    German Version

  • Cooliris Integration – My Plans

    With the 5er version Fast Gallery got so much more handy. The latest changes with the plugable Frontend make development for fast gallery a pleasure as you don't have to be afraid anymore killing the whole module when you only want to switch presentation. It's really a charm.

    Well, somebody asked about
    http://www.cooliris.com/ support. I do think this does look really cool. So I looked into it. The bummer is, the cooliris needs a feed… which is kinda cool, but again for Fast Gallery not really handy. Well here is my plan of attack: Use the fast gallery API module (which I started developing, but kinda lost interest).

    The in detail plan looks like this:

    1. Extend hook_fast_gallery_info

    Allow two more parameters: type and source. Type would be "feed" and source would be the base path of where to find the feed (something like fast_gallery_api/get)

    2. Fix fast gallery api module

    As said this needs some love. Probably we just need to test it a little be in depth, maybe an additional handler and make sure that the feed is being outputted correctly so that cooliris will understand the format.

    3. embed cooliris

    That's probably going to be the easiest part. Just past in the object tag and point the source to where specified.

    I guess 1 and 3 are a matter of 15 minutes, while 2 is going to take some time. So if any of you guys wants to help… Get your hands dirty and start coding. The plattform for patches would be in the fast gallery issue queue.

  • Fast Gallery 6.5.4 – Galleria Integration

    Heute mal wieder ein wenig an Fast Gallery gebastelt. Hier was dabei herausgekommen ist. Das Galleria Modul wird integriert (Galleria ist dazu nicht notwendig). Fast Gallery hat die nötige Javascript Bibliothek mit dabei.

    Galleria Ansicht sieht dann wie folgt aus.

    Die Standardansicht sieht wie folgt aus:

    Für Entwickler ist zudem weiter interessant, dass das Frontend plugable ist. Das will heissen, es muss lediglich ein Hook implementiert werden, und dann kann ein zusätzliches Frontend inzugefügt werden. Ich bin noch auf der Suche nach coolen Galerien.

    Wäre cool, wenn jemand den Hook implementiert und ein Frontend für Fast Gallery schreibt. Die Galleria Ansicht braucht noch ein wenig Arbeit (Ordner und Titel müssen noch unterstützt werden), aber das ist a

  • Scrum in einem Drupalprojekt

    Seit einigen Wochen setzen wir ernsthaft Scrum als Projektmethodik ein. Noch gibt es vieles zu lernen, aber die ersten Wochen sind sehr positiv verlaufen. Hier ein paar Grundsätze:

    • Team besteht aus 4 Entwickler und 1 Designer
    • Productowner ist leider nicht auf Kundenseite
    • Scrummaster (auch Mitglied des Teams)
    • Sprints dauern 2 Wochen
    • Team arbeitet pro Woche 3 Tage am Projekt (grundsätzlich Di – Do)

    Da die ganzen Scrummethodik noch sehr jung ist, haben wir beschlossen, bereits nach einer Woche eine kleine Retrospektive zu machen. Daraus resultierten 3-4 Punkte konkrete Punkte, welche wir ändern/verbessern wollen (nicht nötig dafür noch eine weitere Woche zu warten, besonders da die Projektdauer sehr kurz ist).

    Fazit: Sehr positiv. Besonders hervorzuheben ist vor allem die Motivation und der Teamgeist, welcher viel stärker zur Geltung kommt. Jeder ist bedacht, die Tasks bis zum Sprintende zu erfüllen und auch bereit Aufgaben von anderen Mitgliedern zu erfüllen. Dadurch entsteht ein viel besserer Wissenstransfer.

    Negativ: Kommunikation zum Kunden hin noch nicht optimal. Bei offenen Fragen dauert es einfach noch zu lange, bis Antworten zurückkommen. Ist nicht direkt etwas, was wir ändern können, aber muss sicher bei Projektbeginn klip und klar kommuniziert werden und vor allem müssen auch die Konsequenzen aufgezeigt werden: Verzögerung des Projektes.

    Und das Beste: Man kann die ganzen Scrumansätze den eigenen Gegebenheiten und Eigenheiten anpassen. Ich kann es also nur weiterempfehlen.

  • Fast Gallery – Introduction for developers

    This blogpost should give a quick kickstart to every developer who is interested in helping to advance Fast Gallery. The architecture is intended to have a swapable storage engine. So far I've only written one storage engine, which means that interfaces are not 100% clearly defined, but would instead need some work when actually going to be used in practice. First a quick overview over the files and what their responsibilities are.

    • fast_gallery-image-wrapper.tpl.php: template file to display the image
    • fast_gallery.admin.inc: the general admin stuff (UI), that would be used by any storage engine (setting up galleries, scanning galleries…)
    • fast_gallery.cache.class.php: incase Imagecache is not available there's a simple caching class, that creates thumbnails and caches them.
    • fast_gallery.class.php: this is the heart of the module. Here we recursively explore directories for images and send them to the storage engine or get images from the storage engine and return them to the frontend
    • fast_gallery.css: if you are developing, you should know what this is for 😉
    • fast_gallery.info: same here
    • fast_gallery.install: and same here
    • fast_gallery.module: Mostly it's just implementations of hooks and actually displaying the gallery in fast_gallery_alias()
    • fast_gallery.test: I started once writing some tests…. this really needs some work!
    • FGImage.class.php: Internally Fast Gallery treats images as objects of this class.

    Ok, then we have a couple folders:

    • images: just some images
    • integrations: possible integrations into other modules. So far: features integration
    • modules: Other modules for fast gallery. I started once the Fast Gallery API module, which should provide some kind of REST API… but it's not there yet
    • storageengine: well this contains some classes and interfaces that are responsible for actually storing and retrieving images and hierarchy retrieved from directories
    • tests: just some folders that are used when doing the simpletests

    Just some more info on the storageengine folder:

    • Istorage.php: contains and interface that all possible storageengines must implement.
    • default.config.inc: Well, just some UI stuff for storageeninge specific configuration
    • default.storage.inc: the actual storage engine, that stores data into the db, makes sure hierarchy is correct and returns the right images depening on the path.
    • node.config.inc, node.storage.inc: sample data to build a nodestorage, which was actually my goal at a given point…. but unfortunately not there yet 🙁

    Oky, this is the first attempt. I'll write another blogpost and describe some of the important concepts in detail.

  • Inplace Editing – Fast Gallery

    In der neuen Version von Fast Gallery gibt es mal wieder ein neues Feature. Bilduntertitel können über IPTC ausgelesen werden. Dabei gibt es mehrere zur Auswahl. Sehr oft ist es jedoch der Fall, das noch gar keine IPTC Daten vorhanden sind. In dem Fall können diese jetzt gleich direkt in der Galerie editiert werden und werden dann ins Bild gespeichert.

    Patrick war so freundlich und hat dafür einen Patch geschrieben. Fertig sieht es dann in etwa so aus:

    Screenshot Fast Gallery inplace editing

    Zudem konnte im neuesten Release auch noch ein Bug behoben werden, so dass auch falls der Ordner leer ist, die Unterordnet aufgelistet werden.

    Dieses Feature basiert auf dem jQuery Edit in Place Plugin, welches separat heruntergeladen und installiert werden muss.

  • Drupal langsame Schreibzugriffe mit innodb

    Mit Drupal 6.17 wurde innoDB eingeführt. Bisher wurde immer myisam verwendet. Die Standardwerte, welche mit MySQL kommen sind für MyIsam ziemlich gut und man kommt schon sehr weit damit. Verwendet man jedoch die Standardwerte für innoDB, dann hat man einen ziemlich Flaschenhals.

    Mit der Installation von Drupal 6.17 stellte ich fest, dass die Seite massiv langsamer wurde. Devel zeigte mir, dass vor allem Schreibzugriffe (z.B. auf die Cachetabellen) sehr langsam vorangingen… (Faktor 100 langsamer als vorher). So habe ich kurzerhand diese Tabellen wieder auf MyIsam zurückgesetzt und siehe da, es ging wieder schneller.

    Heute hatte ich ein bisschen mehr Zeit, um ein wenig herumzuspielen. Schlussendlich habe ich die Lösung gefunden, den Flaschenhals zu öffnen:

    innodb_flush_log_at_trx_commit = 2

    Standardmässig ist er gar nicht gesetzt. Sobald ich den auf 2 gesetzt habe ist die Seite nur so "geflogen". Performance hat auch mit innoDB massiv zugenommen. Was ist passiert. Wenn innodb_flush_log_at_trx_commit auf 2 gesetzt ist, dann wird nur jede Sekunde etwas auf die Festplatte geschrieben, sonst wird jeder Schreibbefehl auch gleich auf die Festplatte geschrieben, was natürlich viel langsamer ist.

    Also… ich bin überhaupt kein MySQL Perfromance Guru, aber das scheint mir eine sehr einfache und effiziente Lösung zu sein.

  • Übersetzungen in Drupal t vs tt

    Übersetzungen in Drupal sind so eine Sache und es gibt diverse Funktionen. Ich habe ja selber nicht gewusst, dass es neben t() auch noch tt() gibt und ich muss sagen tt() ist genial 🙂 Hier mal eine kleine Erklärung, welche ich dazu gefunden habe… sehr plausibel erklärt, warum t() nicht überall verwendet werden soll/darf.

    Im folgenden ein Auszug aus der Drupal Mailing Liste.

    So you're suggesting that currently the "correct" way to make text
    stored in the database translatable is to use tt()?

    I don't know of a better way. We tried to get people to review approaches for this in core for Drupal 6, but nobody showed up at that time, so no such solution got into Drupal 6 consequently. Given lack of interest it did not get into Drupal 7 either as it seems.

    Why is tt() more
    correct than t()? Isn't tt() going to end up orphaning the translations
    if the database text gets changed, the same as t()?

    I did not look into the current implementation (tt() is using some abstractions :), but the idea is that unlike t(), you provide tt() with more detailed meta information on the "location" of the string, so you tell it that "this is status label number 3 from mymodule", so when the status label 3 is updated, the string to translate can be updated without leaving orphan strings behind. With t() you lack this metainformation on the string (even in Drupal 7, unless you abuse the context system to hell which is however not supposed to used in this granularity given that it makes translation sharing impossible).

    Doesn't tt() still
    have the same problem when the database text gets changes to non-english
    language?

    It segments this problem to at least the non-default textgroup. There is obviously no way we can tell whether a string is English or not and it is pointless to keep trying to get users to enter English text at all times on a localized site. That would be crazy.

    Is what this is really solving is avoiding a misnomer,
    avoiding putting "database defined text" into the "code defined text"
    locale group?

    The Drupal 6 textgroup system lets you segment strings and as implemented with tt(), it also lets you use the location information to update and look up strings based on the objects they relate to. These are all unavailable if you use t(). Also, t() has some other niceties, like caching short strings for easy lookup. Now if we'd tell people to translate things like taxonomy with t() itself, then you can easily end up with a huge cache of short strings (including all your taxonomy terms) loaded up on every page. Pretty useless and resource consuming.

    We could say you might still somewhat safely use t() in some user input cases, but it would still go with the leftover stale strings, mixing up the English and non-English text in the database and on the translation UI, etc. Textgroups and tt() exploiting them with the location information attempts to solve these problems as well as not letting user input go to the t() cache loaded on every page. which is designed with the UI text mass in mind.

    What about Mike's suggestion to create a support.locale.php file whose
    sole purpose is to expose default database strings? Is that practice
    frowned upon? At this time it seems like the simplest solution, though
    if someone decides to add their own custom states and/or priorities they > won't be translatable without also hacking the support.locale.php file.
    How is this solved? What is the proper way to be sure that any text
    stored in the database is exposed to the translation system, even text
    that may be added later by the user?

    As said, while technically t() might look like it solves your problems, I'd advise against it. See above.

    Gábor

    Im Detail würde es dann so aussehen:

    <!–?php
    function mymodule_locale($op = 'groups', $group = NULL) {

    switch ($op) {

    case 'groups': return array('mygroup' => t('My Group')); }

    }

    function mymodule_somefunction() {

    //…

    tt('mygroup:the_location', $string);

    //… }

    ?>

    Weitere Ressourcen:

  • Views API für Entwickler

    Am heutigen Tag, habe ich mich ein wenig mit der Drupal Views API herumgeschlagen. Ich habe zum ersten mal ein eigenes Style Plugin für Views geschrieben. Aller Anfang ist schwer und so habe ich mich am Anfang auch ein wenig gequält, aber bin dann schlussendlich sehr schnell vorangekommen.

    Wo fängt man am Besten an? Nun, ich lerne am Liebsten von Vorlagen und Beispielen. Ich habe mir also einfach so ein Modul geschnappt, welches ein Style Plugin implementiert und zwar Views Slideshow. Das Modul ist relativ einfach und man blickt schnell durch.

    Hookmässig ist eigentlich nur hook_views_api und hook_views_plugins zu implementieren, wobei der hook_views_plugins in meinmodule.views.inc muss. In diesem Hook wird das Plugin dann definiert. Dann gibt es eine weitere Datei, welche eine bestimmte Namenskonvention einhalten muss, welche das eigentliche Plugin implementiert. Hier wird eine Klasse implementiert, welche von einem Standardplugin abgeleitet wird.

    Je nachdem, was für ein Plugin man schreiben möchte, kann man die Methoden der Klasse selber implementieren, oder man implementiert die Methode nicht, und lässt die übergeordnete Klasse die arbeit erledigen. Damit man weiss, was für Methoden zur Verfügung stehen ist die Views Dok ausgezeichnet.

    Dieser Beitrag ist ziemlich knapp… ja ich weiss, aber im Moment habe ich gerade nicht viel mehr Zeit. Es sei an dieser Stelle nur gesagt, dass es sich doch für das eine oder andere Problem lohnen kann.