Archiv für den Monat März 2012

Zwischenfazit Social Media – Teil 4

Gemeinsame Wissensbasis

image

Wenn man in einem großen, heterogenen Team arbeiten will, so müssen erst alle Beteiligten auf einen gemeinsamen Wissensstand gebracht werden. Auf dieser Basis kann im Anschluss die Kompetenz erweitert werden. Letzteres wird umso wichtiger, je stärker das Thema im Unternehmen integriert wird. Denn – und dessen sollte man sich immer bewusst sein – werden Diskussionen untereinander und Rückfragen rapide zunehmen. Typischerweise entstehen solche Gespräche z.B. beim Kaffeetrinken oder bei Zigarettenpausen. Initiiert werden diese vor allem durch sogenannten Meinungsmacher, zu welchen primär die Abteilungsleiter zählen. In diesen Gesprächen gilt es zu punkten, um Social Media im Unternehmen erfolgreich etablieren zu können. Natürlich ist es gerade für Jugendliche und Auszubildende schwer, eine Thematik – besonders eine derart ambivalente – mit kompetenten Höhergestellten, die langjährige Erfahrung besitzen, zu erörtern! Dies wird umso leichter, je besser man mit der Materie vertraut ist. Allerdings ist es auch umso schwieriger, je stärker das Neue im Gegensatz zu besagter Erfahrung steht.

Dementsprechend waren die ersten Meetings de facto reine Schulungen. Das umfasste auch typische Gegenargumente und deren Entkräftung. Darüber hinaus wurden Domänenbegriffe erläutert, Diskussionen geprobt (auch wenn den Beteiligten das zu dem Zeitpunkt nicht klar war), Vorträge besucht (z.B. die Social Media Night in Stuttgart) und Fachliteratur erarbeitet. Einen wesentlichen Punkt haben wir aber immer wieder genannt: Im Zweifelsfall die Diskussion mit dem Verweis auf später verschieben, dass zuerst mit der Gruppe gesprochen werden muss, bevor dazu eine verbindliche Aussage gegeben werden kann.

Werbeanzeigen

Castle Windsor – Forwarding

As I just noticed, since v3.0 there is a new useful possibility for registering multiple services by one component. Take a look at this page.

   1: Component.For<IFoo, IBar>().ImplementedBy<FooBar>();

You want a sample?

   1: yield return Component

   2:     .For<ICalculateOrderProposals, IShowOrderProposals>()

   3:     .ImplementedBy<ArticleOrderProposals>()

   4:     .LifestyleSingleton();

I wanted to seperate the concerns “calculate order proposals” and “show order proposals” in two interfaces in order have more transparency and directness in the consuming components. But because of cohesion i wanted to implement this in one class.

Nice work guys!

Meine tägliche Portion Git

Wer eine Änderung gepusht hat und diese rückgängig machen will, sollte wie folgt vorgehen:

  • Gleich alle Entwickler informieren, dass sie nicht mehr pullen sollen (idealerweise hat noch niemand den neuen Stand gepullt!)
  • Über den Befehl “git reset —hard head~1” (geht eine Revision zurück) oder über “git reset —hard  fa0f23d” (wobei fa0f23d dem SHA des Commits entspricht, auf den man zurück will), könnt ihr zunächst lokal den gewünschten Stand wiederherstellen. Über git log könnt ihr auch die Historie anschauen.
  • Danach setzt ihr mit “git push -f origin master” das öffentliche Repository zurück

Anmerkung: Das funktioniert z.B. nicht, wenn der entsprechende Developer nicht die benötigten Rechte hat oder Git so eingestellt ist, dass es “git push -f” nicht zulässt. Wie ihr dieses Problem löst und einen alternativen Weg findet ihr hier (Eintrag 2 anschauen!).

Entity Framework – Nullable Bug

As I experienced today, there’s a bug in the Entity Framework. Let’s have a look at the following scenario:

Screenshot 1

image

 

Screenshot 2

image

 

In Screenshot 1 you can see a table with two datetime columns. One is marked as nullable whereas the other is not. I used Database First approach to generate the Entity Data Model. Screenshot 2 shows you the auto-generated Entity. Take a look at the following properties:

imageimage

Notice the highlighted setting “Nullable” of the generated property “MyNullableDateTime”: It’s none instead of what it should be – true. Nevertheless, the generated code is all fine:

   1: [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]

   2: [DataMemberAttribute()]

   3: public Nullable<global::System.DateTime> MyNullableDateTime

   4: {

   5:     get

   6:     {

   7:         return _MyNullableDateTime;

   8:     }

   9:     set

  10:     {

  11:         OnMyNullableDateTimeChanging(value);

  12:         ReportPropertyChanging("MyNullableDateTime");

  13:         _MyNullableDateTime = StructuralObject.SetValidValue(value);

  14:         ReportPropertyChanged("MyNullableDateTime");

  15:         OnMyNullableDateTimeChanged();

  16:     }

  17: }

  18: private Nullable<global::System.DateTime> _MyNullableDateTime;

Unfortunately, if you change the column in the database to be no longer nullable and furthermore, you refresh your model, this will cause a build error:

>>Error 3031: Problem in mapping fragments starting at line 51:Non-nullable column >>DateTimeTest.MyNullableDateTime in table DateTimeTest is mapped to a nullable entity property.

Meine tägliche Portion Git

Wer eigene Merge Tools in Git verwenden will, der muss ein paar Kleinigkeiten beachten:

1. %userprofile%\.gitconfig anpassen: Neuer Abschnitt für das Mergetool der eigenen Wahl anlegen

[mergetool "P4"]
    cmd = /Pfad/p4merge-merge.sh \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
    trustExitCode = true

Gegebenenfalls auch unter [merge] dieses als Standard definieren:

[merge]
    tool = P4
    log = true

 

2. Shell-Skript schreiben und dort ablegen, worauf ihr in der .gitconfig verwiesen habt

#!/bin/sh
script_dir=/Pfad

local="$($script_dir/cygpath –mixed –absolute "$2")"
base="$($script_dir/cygpath –mixed –absolute "$1")"
baseUnixFormat="$($script_dir/cygpath –unix –absolute "$1")"
remote="$($script_dir/cygpath –mixed –absolute "$3")"
result="$($script_dir/cygpath –mixed –absolute "$4")"
tool="/Pfad/P4Merge/p4merge.exe"

if [ ! -f "$baseUnixFormat" ]
then
    base="$($script_dir/cygpath –mixed –absolute $script_dir/p4merge-empty.txt)"
fi

"$tool" "$local" "$remote" "$base" "$result"

 

Achtet genau auf die Pfade! Für Teams bietet sich an, dass man alle Tools und Skripte ins Repository mit aufnimmt. Danach erstellt man ein symbolisches Verzeichnis auf der Platte, welches bei jedem Entwickler auf den Pfad des Repository verweist. Wir haben uns z.B. darauf verständigt, dass jeder Entwickler ein Verzeichnis D:\Development\Repository haben muss. Bei mir zeigt das dann beispielsweise auf G:\heco\comwork. Bei dem Kollegen wiederum auf einen anderen Pfad. Aber da wir mit dem symbolischen Verzeichnis arbeiten, können wir alle die Skripte und Tools verwenden ohne sie anpassen zu müssen. Da die Git\.gitconfig wiederum pro Entwickler konfiguriert wird, kann trotzdem jeder das Merge Tool seiner Wahl als Standard einstellen.

Noch zwei wichtige Punkte:

  • Im Pfad muss eine p4merge-empty.txt liegen, sonst schmeißt das Skript einen Fehler. Die Dateien wird verwendet, wenn es beim Merge keine gemeinsame Basis gibt, also statt /dev/null. Damit haben die meisten Programme und Windows Probleme.
  • Ich verwende das Kommandozeilentool cygpath (Teil von cygwin), um Windows Pfade in Unix Pfade zu konvertieren. Wenn ihr dieses nicht verwendet, dann müsst ihr die Befehle abändern und alle Pfadangaben im Unix Format angeben.

Weiterführender Link zum Blogeintrag von agross.

Streit zwischen YAGNI und Open Closed Principle

Kürzlich hatte ich ein interessantes Gespräch darüber, ob man durch die Einhaltung von OCP YAGNI über den Haufen wirft. Hintergrund war der, dass ich persönlich meine Kontrakte (Interfaces) immer in eine separate Assembly lege. Wenn die Implementierung beispielsweise in “MyProgram.Finances” liegt, dann gibt es eine “MyProgram.Finances.Contracts”, die alle in “MyProgram.Finances” verwendeten Interfaces enthält. Das ist meine persönliche Konvention für meine Programme. Aus meiner Sicht entspricht dies perfekt dem OCP, da auf diese Art jeder Entwickler in der Lage ist anhand der Contracts seine eigene Implementierung zu schreiben und diese im IoC Container über einen Installer zu registrieren. Er muss dann lediglich meine Implementierung löschen. Generell macht das ganze Vorgehen besonders bei einer IoC Architektur Sinn!

Die andere Sichtweise war nun: Warum Overengineering betreiben, wenn es sowieso nur eine Implementierung gibt und wir rein für uns entwickeln, sprich es keine Dritte gibt, die separate Lösungen anbieten wollen? Das widerspräche dem YAGNI Prinzip. Der Gegenvorschlag war also, dass alles in die gleiche Assembly kommt. Das Interface wäre immer noch Public und die Implementierung internal, da man ja weiterhin die Implementierung im IoC registriert.

Das Problem ist in dem Fall, dass man eben nicht mehr die Freiheit hat die Implementierung zu überschreiben ohne den bestehenden Code anzufassen.

Persönlich sehe ich es nicht so, dass man gegen das YAGNI Prinzip verstößt, wenn man die Interfaces in eine separate Assembly legt, da man nicht “mehr” Code entwickelt, sondern lediglich die Architektur von Anfang an offen bzw. erweiterbar hält. Natürlich hat man jetzt ein Projekt mehr, aber der eigentliche produktive Code ist der gleiche. Hingegen verstößt man imho definitiv gegen das OCP, wenn man man die Interfaces nicht separiert.

Wie seht ihr das? Feedback über Facebook, Twitter oder WordPress ausdrücklich erwünscht!

Build Server Fehler mit licenses.licx

Ich hatte bereits früher über die Problematik gebloggt, dass Frameworks, welche Lizenzdaten beim kompilieren verarbeiten, auf Build Servern wie Team City Probleme machen können. DevExpress ist so ein Framework. Inzwischen haben wir in unserem Team eine Lösung gefunden: Die licenses.licx Dateien werden werden auf dem Build Server geleert (genauer: die vorhandenen Dateien werden durch leere ersetzt). Jetzt funktioniert alles problemlos, sodass Fehlermeldungen wie die unten der Vergangenheit angehören:

“My Project\licenses.licx(2): error LC0004: Exception occurred creating type ‚DevExpress.XtraTab.XtraTabControl, DevExpress.XtraEditors.v11.2, Version=11.2.5.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a‘ System.TypeInitializationException: Der Typeninitialisierer für "DevExpress.XtraTab.XtraTabControl" hat eine Ausnahme verursacht. —> System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. —> System.IO.FileNotFoundException: Die Datei oder Assembly "EnvDTE, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.

%d Bloggern gefällt das: