Archiv für den Monat Mai 2013

Lob ist Gift

Seit längerem reduziere ich Lobe konsequent. Ich halte persönlich nichts davon. Nicht gerügt, ist gelobt, sagte unser Azubi kürzlich. In einem sehr interessanten Artikel, den ich aktuell leider nicht zur Hand habe, wurde provokativ formuliert: Die Sucht nach Lob ist schlimmer als jene nach Ecstasy.

 

 image

 

Aus meiner Sicht sollte der Vorgesetzte nicht Zeit in den oftmals inflationären Gebrauch von anerkennenden Worten stecken, sondern in den Aufbau des Selbstverständnis des Mitarbeiters. Wie er seine eigene Rolle, seine Fähigkeiten und seinen Einsatz wahrnimmt, ist maßgeblich entscheidend für den Erfolg der Arbeit, denn daraus entsteht die Freude am Schaffen, aus dem Beruf wird die Berufung. Dann sind die 1-2 Überstunden pro Woche plötzlich nicht mehr verlorene Freizeit, sondern ein Einsatz, der sich gut anfühlt, den man positiv als eigene Weiterentwicklung betrachtet. Im Folgenden will ich genauer erklären, wie das gemeint ist.

Jemand, der den gesamten Samstag beispielsweise mit Gartenarbeit verbracht und “etwas bewegt” hat, der schöpft am Abend bei einem kühlen Bier, während er das Geleistete betrachtet, mehr Zufriedenheit daraus, als wenn ein Bekannter beim Vorbeigehen ein “fleißig, fleißig” oder “das sieht aber schön aus” über den Zaun wirft.

Als Mitarbeiter sollte man sich darüber im Klaren sein, dass der Vorgesetzte in den allermeisten Fällen so weit weg vom Geschehen ist, dass ein überschwängliches Lob kein Gradmesser für die eigene Leistung sein kann. Es hat sicherlich jeder einmal ein Lob für etwas bekommen, dessen Arbeit er selbst nicht als sonderlich schwierig oder gar als weniger gut empfunden hat. Aus der eigenen Zufriedenheit lässt es sich hingegen viel mehr Motivation schöpfen. Betrügereien gibt es hier nicht, denn ich weiß, ob ich etwas für meine Verhältnisse gut oder schlecht gemacht habe.

In meinen Deutschaufsätzen musste ich früher höchstes Engagement einbringen, um auf eine 2-3 zu kommen, welche ich dann voller Stolz wie andere eine 2 in Mathe feierten. Mir war klar, dass ich das Maximale aus meinem Können herausgeholt hatte. Hingegen waren gute Noten in Mathe eher nebensächlich, da mir der Schwierigkeitsgrad im Verhältnis wesentlich geringer vorkam. Friedrich Schiller sagte einmal:

Wer immer das Beste gegeben hat, bleibt unvergessen.

Das Beste bezieht sich auf die eigenen Möglichkeiten. Deswegen sollte ein Vorgesetzter dem Mitarbeiter helfen die eigenen Möglichkeiten auszuschöpfen. Dies ist aber nach meinem Verständnis nur möglich, wenn die Arbeitskraft den Eindruck hat, dass die eigene Arbeit wichtig ist und dass sie sich darin entfalten kann. Oder anders ausgedrückt: Es muss Spaß machen. Kontrolle und strikte Einschränkungen sind da kontraproduktiv. Jedoch dürfte klar sein, dass in der Arbeitswelt nicht jeder nach Lust und Laune vor sich hinarbeiten kann. Darum geht es mir auch nicht. Die Botschaft muss sein: Als Vorgesetzter will ich dich nicht kontrollieren und dir Regeln vorgeben. Ganz im Gegenteil. Es wäre für beide Seiten von Vorteil, wenn du eigenverantwortlich arbeitest. Dafür ist es notwendig die mit der Freiheit einhergehenden Pflichten in einer Art wahrzunehmen, die deinen eigenen hohen Ansprüchen genügen müssen.

Aus meiner Erfahrung werden in aller Regel die eigenen Ansprüche des Mitarbeiters höher sein als die des Vorgesetzten. Falls dem doch nicht so ist, gibt es Mittel und Wege, um einen Abgleich herbeizuführen. Ein gemeinsames Verständnis und die Formulierung der jeweiligen Erwartungen, wie sie z.B. in Mitarbeitergesprächen aufgebaut werden können, sind gute Ansätze. Es ist leicht nachzuvollziehen, dass genau aus diesem Grund zwei Punkte bei den Zielformulierungen beachtet werden müssen:

  • Ziele müssen gemeinsam formuliert werden
  • Der Mitarbeiter muss eigene Ziele einbringen können

Motivationsgespräche sind ebenfalls ein gutes Instrument, viel besser als das täglich schnell verpuffende Lob. Beispielhaft könnte folgende Frage an den Mitarbeiter gerichtet werden:

“Willst du die Entscheidungen über eingesetzte Technologien bei der Entwicklung treffen? Und willst du so unabhängig werden, dass 1-2 Tage Home Office möglich werden. Dann musst du für die Rolle ein Level an Wissen und Verlässlichkeit erreichen, das den besprochenen Zielen entspricht.”

Werbung

Castle Windsor Dependencies Tracking

Deployments für Anwendungen zu erstellen, welche modular über einen IoC Container wie Castle.Windsor aufgebaut sind, ist nicht ganz simpel. Zumindest ging es mir so, als ich vor der Herausforderung stand eine Konsolenanwendung zu deployen, welche im Einstiegspunkt eine Komponente auflöst und darauf eine Methode aufruft, die den gesamten Bearbeitungsprozess startet. Alle weiteren Abhängigkeiten werden dann über den internen Graphen des Containers aufgelöst. Findet er eine Komponente nicht, kommt es zur Exception:

image

Ich halte es in meinen Projekten so, dass die Kontrakte immer in einer separaten Assembly liegen. Als Namenskonvention erhält die DLL ein “.Contracts”. Ein Beispiel:

  • UAR.Demo //Implementierung
  • UAR.Demo.Contracts //Kontrakte

So weit wie möglich sind dann in der Implementierung alle Klassen internal oder private. Über einen öffentlichen Installer wird beim Start der Anwendung die Registrierung der angebotenen Kontrakte samt derer Implementierungen im Container vorgenommen.

Da demzufolge keinerlei Referenzen mehr zwischen den Implementierungen bestehen und ich in der oben erwähnten Konsolenanwendung nun nur genau einen Einstiegspunkt habe, der sich die initiale Komponente auflöst und startet, fehlen weitere benötigte Assemblies.

Als ich über Twitter das Castle Team diesbezüglich angesprochen habe, kam folgende Antwort:

it might not be trivial. You can walk the graph, but better option would be to have clean layering so it’s obvious

Leider half mir die Aussage nicht weiter, da ich keinen „clean layering”-Ansatz sehe, der besagtes Problem auflöst. Vielleicht kann mir einer der Leser weiterhelfen?

Als Lösung habe ich mich in das Event der Komponentenerstellung von Castle.Windsor gehängt. Wie dies funktioniert, seht ihr in dem Webcast. An dieser Stelle will ich noch den Code veröffentlichen und um Feedback bitten.

 

 

Extension Methods für IWindsorContainer:

   1: static class CastleWindsorExtensions

   2:     {

   3:         public static IWindsorContainer EnableDependencyTracking(this IWindsorContainer container)

   4:         {

   5:             var containerInfo = new ContainerDependencyTracker();

   6:  

   7:             container

   8:                 .Register(Component.For<ITrackContainerDependencies>()

   9:                 .Instance(containerInfo)

  10:                 .LifestyleSingleton());

  11:  

  12:             container.Kernel.ComponentCreated += containerInfo.AddRequiredAssembly;

  13:  

  14:             return container;

  15:         }

  16:  

  17:         public static IWindsorContainer EnableMemoryDiagnostic(this IWindsorContainer container)

  18:         {

  19:             //have a look at http://docs.castleproject.org/Windsor.Performance-Counters.ashx?HL=lifecycledcomponentsreleasepolicy

  20:             var diagnostic = LifecycledComponentsReleasePolicy

  21:                                 .GetTrackedComponentsDiagnostic(container.Kernel);

  22:             var counter = LifecycledComponentsReleasePolicy

  23:                                 .GetTrackedComponentsPerformanceCounter(new PerformanceMetricsFactory());

  24:             container.Kernel.ReleasePolicy = new LifecycledComponentsReleasePolicy(diagnostic, counter);

  25:  

  26:             return container;

  27:         }

  28:     }

 

Interface für die Tracking Implementierung:

   1: public interface ITrackContainerDependencies

   2: {

   3:     IEnumerable<Assembly> RequiredAssemblies { get; }

   4:  

   5:     int RegisteredComponents { get; set; }

   6:  

   7:     void AddRequiredAssembly(ComponentModel model, object instance);

   8:  

   9:     StringBuilder ResolvedComponentsInARow { get;}

  10: }

 

Implementierung für das Tracking:

   1: class ContainerDependencyTracker : ITrackContainerDependencies

   2: {

   3:     public ContainerDependencyTracker()

   4:     {

   5:         ResolvedComponentsInARow = new StringBuilder();

   6:     }

   7:  

   8:     readonly List<Assembly> _requiredAssemblies = new List<Assembly>();

   9:  

  10:     int Number;

  11:     public StringBuilder ResolvedComponentsInARow

  12:     {

  13:         get;

  14:         private set;

  15:     }

  16:  

  17:     public IEnumerable<Assembly> RequiredAssemblies

  18:     {

  19:         get

  20:         {

  21:             return _requiredAssemblies.Distinct().ToList();

  22:         }

  23:     }

  24:  

  25:     public int RegisteredComponents

  26:     {

  27:         get;

  28:         set;

  29:     }

  30:  

  31:     public void AddRequiredAssembly(ComponentModel model, object instance)

  32:     {

  33:         Number += 1;           

  34:         ResolvedComponentsInARow.AppendLine(string.Format("{0}: {1}", Number, model.Implementation));

  35:  

  36:  

  37:         foreach (var service in model.Services)

  38:             _requiredAssemblies.Add(service.Assembly);

  39:  

  40:         _requiredAssemblies.Add(model.Implementation.Assembly);

  41:     }

  42: }

 

In dem Video gehe ich auch kurz auf die Auffindung von Speicherlecks ein. Die Implementierung ist oben in den Extensions enthalten. Es sei an dieser Stelle auf folgende Seite im Castle Wiki verwiesen.

Entity Framework Webcasts – Testing

Im siebten Teil meiner Entity Framework Webcast Serie widme ich mich dem Thema Testing. Zunächst nehmen wir uns die fertigen Queries vor, welche sich auch gut ohne Datenbank testen lassen. Schließlich will nicht jeder zum Testen einer Abfrage immer eine entsprechende Datenbank hochfahren und die Daten dafür erzeugen.

Danach stellen wir in einem Mini-Business-Pseudo-Layer ein Szenario nach, welches uns dedizierte Daten für die weitere Verarbeitung liefert, sodass das Testen der Geschäftslogik ebenfalls ohne Datenbank erfolgen kann.

Als BDD Framework für die Unit Tests verwende ich Machine.Specifications und als Mocking Framework kommt FakeItEasy zum Einsatz.

Hier noch die zwei Code Beispiele:

 

Beispiel 1: Testen der Query

   1: [Subject(typeof(GetAddressByCity))]

   2: public class When_addresses_contains_exactly_one_matching_entry

   3: {

   4:     static GetAddressByCity Sut;

   5:     static List<Address> Addresses;

   6:     static Address Actual;

   7:     static Address TestCity;

   8:  

   9:     Establish context = () =>

  10:     {

  11:         TestCity = new Address {City = "test city"};

  12:         Addresses = new List<Address>

  13:         {

  14:             new Address {City = "Karlsruhe"},

  15:             TestCity

  16:         };

  17:         Sut = new GetAddressByCity("test city");

  18:     };

  19:  

  20:     Because of = () =>

  21:     {

  22:         Actual = Sut.Execute(Addresses.AsQueryable());

  23:     };

  24:  

  25:     It should_return_exactly_this_address = () => 

  26:             Actual.ShouldEqual(TestCity);

  27: }

 

Beispiel 2: Testen von Geschäftslogik

   1: class EmployeeBusinessLogicSpecs

   2: {

   3:     [Subject(typeof(EmployeeBusinessLogic))]

   4:     class When_hire_date_is_unknown

   5:     {

   6:         static IUnitOfWork Uow;

   7:         static EmployeeBusinessLogic Sut;

   8:         static Employee DummyEmployee;

   9:  

  10:         Establish context = () =>

  11:         {

  12:             DummyEmployee = new Employee {EmployeeID = 1, 

  13:                     FirstName = "Uli", LastName = "Armbruster"};

  14:  

  15:             Uow = A.Fake<IUnitOfWork>();

  16:  

  17:             A

  18:                 .CallTo(() => Uow.ExecuteQuery(

  19:                     A<GetEmployeeById>

  20:                     .That

  21:                     .Matches(q => q.EmployeeId == DummyEmployee.EmployeeID)

  22:                                   ))

  23:                 .Returns(DummyEmployee);

  24:  

  25:             Sut = new EmployeeBusinessLogic(Uow);

  26:         };

  27:  

  28:         Because of = () => Sut.EnsureValidHireDate(DummyEmployee.EmployeeID);

  29:  

  30:         It should_update_it = () => DummyEmployee.HireDate.ShouldNotBeNull();

  31:  

  32:         It should_save_the_changed_hire_date = () => A

  33:             .CallTo(() => Uow.Commit())

  34:             .MustHaveHappened(Repeated.Exactly.Once);

  35:     }

  36: }

 

 

Weitere Quellen:

%d Bloggern gefällt das: