- Posted by robert on März 8, 2010
Gerade auf meinem Monitor gesehen, bei dem Versuch für eine MS-SQL Datenbank einen dump zu erzeugen…
Nach dem Database-Publishing-Wizard gescheitert ist, hat SQLDUMP die Aufgabe mit Bravour gelöst :-)

- Posted by Stefan on Januar 29, 2010
Macht das Leben leichter:

- Posted by robert on Januar 22, 2010
Ziel dieses Posts ist es aus Mitverwender-Perspektive unsere Nutzungsmuster von Google-Wave zu beschreiben und die bisherigen Eindrücke zu nutzen, damit wir (noch) effizienter mit diesem neuen Kollaborationswerkzeug umgehen können.
Bisher nutzen wir Google Wave für folgende Aktivitäten:
- Meeting-Protokolle
- gemeinsames Entwickeln von Ideen/Konzepten
- gemeinsames Entwickeln von Dokumenten (Verträge, Angebote,..)
- Notizen für Gruppenarbeiten
- Notizen individuell
- was noch(?)
Metadokumente, Wave ergänzt ohne zu ersetzen
Etwas das sehr gut zu funktionieren scheint, ist die Nutzung unseres Wikis um Meta-Infos zu verwalten. So haben wir zum Beispiel Linklisten auf Meeting-Protokolle die sich in wave befinden (Vorher waren die Protokolle selbst im Wiki), aber auch Verweise auf waves mit Ideen und Konzepten.
Das Wiki scheint durch Google Wave eher noch an Bedeutung zu gewinnen und stellt einen festen Rahmen und eine Struktur dar, in der wir uns leicht zurechtfinden können.
Waves sind zwar Hypertext fähig, haben aber doch eher den Charakter einer Dokumentensammlung, der man durch Ordner und Tags Herr werden kann.
Franziska meinte mal, dass waves gar nicht unähnlich dem Verschicken von Worddokumenten mit Anmerkungen sind – so empfinde ich das erstaunlicherweise auch – auch wenn waves praktischer sind. (Vielleicht wird auch aus dem Microsoft-Office-Online Umfeld eine spannende Antwort auf Google-Wave kommen.)
Echtzeit vs. zeitlich versetzt
Die Möglichkeit direkt zu sehen wenn andere im Dokument schreiben ist reizvoll, hat aber potentiell auch Probleme. Persönlich finde ich es teilweise in Meeting-Situationen ablenkend, genau wie Skype Kommentare, das während man zuhört oder redet neuen Information herein flattern. Vielleicht ist das auch nur eine Konzentrations- und Trainingsfrage. Gerade bei Gesprächen mit mehr als 3 Teilnehmern könnte es die Meeting-Qualität aufwerten wenn ein gemeinsames Dokument als Metaebene genutzt wird.
Denkbar wäre zum Beispiel, dass jeder Teilnehmer seine "Status" in der wave pflegt und kommentiert - Beispielsweise mit Feedback zur Situation wie etas: "langweilig", "zu lang", "1+ von mir" usw. . Vielleicht können wir das ja mal bald mal ausprobieren :-)
In Telefonkonferenzen mit Kunden könnte ein solcher Status auch das virtuelle anstoßen unterm Tisch ermöglichen (auch wenn das bei uns bisher noch nicht nötig war) und wir stolz auf unseren partnerschaftlichen Umgang mit unsere Kunden sind.
Manchmal finde ich störend das andere vielleicht verschiedene Versionen eines Kommentares sehen - denn ich möchte ja eigentlich das Ergebnis veröffentlichen und nicht die Überlegungs-Zwischenstände.
Diskusionsthreads
Die Möglichkeit direkt im Text zu kommentieren führt manchmal zu vielen Diskusionsthreads was teilweise verwirrend und übersichtlich sein kann.
Ein gute Strategie scheint mir, wenn wir damit beginnen würden Threads aufzuräumen und wieder zu löschen. Das Ergebnis der Threads könnten dann wieder im ursprünglichen Dokument angepasst werden. Sonst entstehen Diskusionen wie in Foren und das Dokument lebt nicht - sondern nur die Diskussion drum herum. Damit sich auch jemand verantwortlich oder berechtigt fühlt, könnte es nützlich sein einen Dokumenten-Owner einzuführen. Dieser darf solche Bereinigungen nicht nur durchführen, sondern ist auch dazu angehalten und könnte von Kollaborateuren dazu aufgefordert werden.
Zusammenfassung
Google-Wave ist mächtiges Werkzeug das (trotz Beta-Zustands ) gut bei uns angekommen ist. Wie bei der Verwendung von allen andern Kommunikationsmedien und Werkzeugen will der Umgang gelernt und mit Kollegen (Kollaborateuren) abgestimmt sein.
(Wer noch eine Einladung braucht, kann mir einfach schreiben :-) )
- Robert
- Posted by oliver on Januar 15, 2010
Einige Zeit nun schon wurmte mich, dass immer, wenn ein User-Objekt von NHibernate geladen wurde, direkt im Anschluss ein UPDATE geschah. Offensichtlich sind die Objekt also dirty, obwohl wissentlich nichts mit ihnen passiert ist.
Unter folgendem Link fand ich gestern auf nhforge eine Möglichkeit für eine nähere Inspektion des Problems, genauer des verschmutzten Objekts. Mit dem dort befindlichen Code und einer kleinen zusätzlichen Methode kann man nun wie folgt gezielt Objekte und deren Properties auf Veränderung prüfen:
1: private void FindDirtyMembers(User user)
2: {
3: var session = _nHibernateHelper.Session;
4:
5: Console.WriteLine("Entity {0}#{1} is dirty: {2}", user.Type, user.Id,
6: session.IsDirtyEntity(user));
7:
8: var dirtyPropNames = session.GetDirtyPropertyNames(user);
9:
10: foreach (var propName in dirtyPropNames)
11: {
12: var original = session.GetOriginalEntityProperty(user, propName);
13: Console.WriteLine("Property '{0}' is dirty! Original: {1}", propName, original);
14: }
15: }
Die Extension-Methods für die Session habe ich in SpeakLib.Utilities\Persistance.NHibernate\SessionExtensions.cs abgelegt.
Mit diesem Check bekam ich beim ersten Test dann auf der Console auch sofort den Fehler zu sehen:
1: Entity UserCampingInfo#1 is dirty: True
2: Property 'MaritalStatus' is dirty! Original: Unspecified
Und tatsächlich steht im Mapping-File für MaritalStatus ein falscher (Enum) Typ:
1: <property name="MaritalStatus" type="SpeakFriend.Utilities.Gender, SpeakFriend.Utilities" />
2:
Was macht NHibernate an dieser Stelle? Ich denke, NH baut ein enum vom Typ Gender zusammen und weist es der Property MaritalStatus zu – wobei dieses dann implizit in den Typen MaritalStatus um. Und das führt dazu, dass das Objekt direkt nach dem Laden dirty ist. Lösung ist also die Anpassung des Mappings auf den richtigen Enum-Typen.
1: <property name="MaritalStatus" type="SpeakFriend.Utilities.MaritalStatus, SpeakFriend.Utilities" />
2:
Gruß, Oliver
- Posted by robert on Januar 3, 2010
Die GIT GUI in deutsch macht oft nicht sonderlich viel Sinn:
Am einfachsten bekommt man eine englische Version, in dem man die Sprachdatei löscht oder umbenennt. Die Sprachdateien der GIT-GUI befinden sich bei mir unter: C:\Program Files (x86)\Git\share\git-gui\lib\msgs
Danach machen die Begriffe auch wieder Sinn :-)

- Posted by robert on Januar 3, 2010
Nach einer Default Installation mit msygit steht kein graphisches DIFF/Merge Tool bereit. Möchte man nun einen Konflikt lösen,
erscheint diese Fehlermeldung:
Abhilfe
Es gibt eine Vielzahl von unterstützten Merge Tools. Mir persönlich hat p4merge am Besten gefallen. Es folgt in kurzen Schritten das einrichten und konfigurieren von p4merge:
1:) Download
P4Merge kann hier: http://www.perforce.com/perforce/downloads/latest.html heruntergeladen werden.
2:) Konfigurieren von GIT.
Der Pfad der Konfigurationsdatei ist für die Default Installation: "C:/Users/[YourUsername]/.gitconfig".
Die .gitconfig muss so erweitert werden:
[merge]
tool = p4merge
[mergetool "p4merge"]
cmd = \"C:\\Program Files\\Perforce\\p4merge.exe\" $PWD/$BASE $PWD/$LOCAL $PWD/$REMOTE $PWD/$MERGED
trustExitCode = false
keepBackup = false
3:) Freude
Ruft man nun aus der git gui “run merge tool” oder von git bash “git mergetool” auf, dann erscheint:
:-)
- Posted by robert on Dezember 22, 2009
In welchem Pfad befindet sich die aktuell verwendete Assembly? Bisher dachte ich immer AppDomain.CurrentDomain.BaseDirectory wäre ein verlässlicher Weg dies herauszufinden. Stimmt aber nicht, den dieser Pfad kann natürlich auch gesetzt werden, was zu unerwarteten Ergebnissen mit unterschiedlichen Test-Runnern führte ("R#" und der "Nunit GUI").
Der richtige Weg: Assembly.GetExecutingAssembly().CodeBase, das den ursprünglichen Speicherort der Assembly zurück gibt.
- Posted by oliver on Dezember 16, 2009
Wenn man viel UI-Funktionalität haben will, braucht man hin und wieder ein paar Dateien Javascript, die diese enthalten – da kommt auf die Dauer einiges zusammen. Wenn man nun versucht, gleichzeitig die Seitengröße unter Kontrolle zu behalten, kommt man schnell auf die Idee, bestimmte JavaScript-Dateien erst dann zu laden, wenn die enthaltene Funktionalität tatsächlich auch benötigt wird.
Ein Schlüssel dazu ist die Methode ScriptManager.RegisterClientScriptInclude, aber leider nur einer. Der zweite, entscheidende Schlüssel ist der hier:
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Diese Zeile muss am Ende jeder auf diesem Wege eingebundenen js-Datei stehen.
Ein ausführliches Beispiel habe ich hier eingestellt, kurz bevor ich dann die Lösung selbst gefunden habe. So ist es manchmal!
Happy coding!
- Posted by robert on Dezember 11, 2009
In den letzten Wochen hatte ich die die Möglichkeit Strategien für Beschleunigung von Builds mit Visual-Studio 2008 und MsBuild zu untersuchen. Hier meine Ergebnisse.
1:) Multiprozessor Build
Visual Studio unterstützt beim Build per Default nur eine Thread. Doch es geht mehr! Das Zauberwort heißt: "msbuild /m".
Detailiert wird das Problem und die Lösung von Scott Hanselman beschrieben:
2:) Einzelnes Output Directory und keine "lokalen Kopien".
Per Default werden Build Ergebnisse in /projekt/bin/<Target>/ kopiert. Alle abhängigen Assemblies werden per Default ebenso kopiert, also auch Build-Ergebnisse anderer Projekte.
Nehmen wir eine Beispiel-Solution mit 50 Projekten. Jedes Projekt hat ungefähr 10.000 Zeilen Code und nehmen wir an die 50 Projekte sind gerechtfertigt. Wenn jedes Projekt mehrfach von anderen Projekten referenziert wird und 10.000 Zeilen ohne .resx Dateien eine DLL Größe von ca.: 250kb ergeben und eine PDB Größe von ca.:500kb, dann ergeben sich, wenn jedes Projekt ungefähr 10x referenziert wird , 10x750kb*50 - also 375 MB zu kopierende Daten. Obwohl eigentlich nur 37MB kopiert werden müssten. Die Lösung für das Problem? Das Build in ein einzelnes Verzeichnis durchführen, ohne die Abhängigen immer wieder zu kopieren. Hierfür muss neben der Pfadangabe für das OutputDirectory folgende Einstellung vorgenommen werden:
3:) Abhängigkeiten minimieren
Wenn I/O Zeiten (siehe 2) kein Problem sind und alle verfügbaren Kerne ausgelastet sind (siehe 1), dann ist der größte verbleibende Zeitfaktor das Auflösen von Abhängigkeiten.
Eine Analyse lässt sich mit dem MSBUILD-Profiler durchführen.

Lösung des Problems? Weniger Abhängigkeiten und Projekte zusammenfassen :-)
4:) .licx Dateien nicht Teil des Projekts
LC.exe ist langsam. Es lässt sich Build Zeit sparen, wenn Lizenz-Informationen nur bei Bedarf in die Assembly "gebaut" werden. .licxs Dateien sollten nicht eingecheckt werden und nicht Teil des Dev-Builds sein.
Was noch?
Solutions entkoppeln und Modular arbeiten? Klar :-) Ein schnelle Entwicklungsmaschine hilft, eine gute SSD Platte und ein schneller Prozessor helfen. Wenn man damit nicht mehr weiterkommt, dann gilt es die Solution zu zerlegen. Als Richtwert sollte ein Clean-Build von 500.000 Zeilen Code (Nettozeilen ohne Kommentare) unter einer Minute liegen.
- Posted by robert on Dezember 8, 2009
Wir hatten gerade eine Diskussion zum Nutzen von “Feature-Branches”, “Long-Running Branches” und “Topic Branches”. Das Gespräch bezog sich auf die Nutzung mit GIT. Zunächst eine kurze Klärung der Begriffe:
- “Feature-Branches”, für ein Feature wird eine neuer Entwicklungszweig genutzt
- “Branch-per-Configuration”, es wird kein physischer branch erzeugt, sondern die Entwicklung erfolgt im Hauptzweig. Ein entwickeltes Feature läst sich per Konfiguration ein und ausschalten.
- “Long-Running Branches”, Ein Branch der länger als ein paar Tage genutzt wird
- “Topic Branch”, Ein Branch der kurzlebig ist. Kurzlebig sind ein paar Minuten oder Stunden.
Aus meiner Perspektive sind Feature-Branches und Long-Running-Branches - wenn möglich - zu vermeiden. Ideal ist sind “Branches per Configuration”, die bei der Entwicklung ein modulares Arbeiten und damit eine gute Architektur erzwingen. Aufwände für das mergen werden vermieden. “Topic Branches“ sind durchweg positiv, wenn sie lokal bleiben und nicht zu entfernten Repositories gepushed werden.
Branch per Refactoring
Es kam auch kurz das Gespräch auf das Thema “Branch per Refactoring” bzw. eine Refaktorisierung wurde als “Feature Branch” bezeichnet. Aus meiner Sicht deutet das auf einen CodeProcess-Smell hin. Die Refaktorisierung ist zu groß. Refaktorisierungsschritte sollten klein sein und ein Arbeitsschritt direkt wieder in den Hauptentwicklungszweig einfließen können.