Archiv für den Monat Juli 2012

MSpec mit ReSharper 7

Soeben habe ich testweise von ReSharper 6 auf Version 7 aktualisiert.

image

Wie auch bei den letzten Upgrades fehlen danach zunächst die Plugins:

image

Zunächst habe ich mit der aktuellen Version 0.5.7 die Installation versucht. Hier fehlt zwar noch das entsprechende Installationsskript für VS2010 + R# 7, aber das ist schnell gebastelt. Leider half dies nichts.

Um eine lange Geschichte abzukürzen: Auch Version 0.5.8 Beta 9 löst das Problem nicht. Ich habe die Info bereits an Alexander Gross von GROSSWEBER weitergeleitet.

Aktualisierung von 23.08 Uhr: AGross teilte mir soeben mit, dass er morgen die finale 0.5.8 bereitstellen will, die das Problem lösen sollte!

Aktualisierung von 23.17 Uhr: Wer nicht warten kann, installiert sich die Version 0.5.8 Beta 11. Danach läuft alles geschmeidig:

Install-Package Machine.Specifications -Version 0.5.8-beta11 -Pre

imageimage

Webcast Strategy Pattern mit IoC

Den Webcast zu diesem Blogeintrag gibt es hier.

Mitarbeitergespräche – Wer fängt an

Heute war es wieder einmal so weit: Es wurden die Mitarbeitergespräche geführt. In der Literatur ist zu lesen, dass man als Vorgesetzter immer als erster sprechen und danach den Mitarbeiter seine Sichtweise darlegen lassen soll. Persönlich halte ich das genau andersherum. Dies hat mehrere Gründe.

Zum einen hat es den Vorteil, dass der Mitarbeiter z.B. beim Feedback (als Teilgespräch von Mitarbeitergesprächen) eine kritische Selbsteinschätzung abliefern muss. Deckt sich diese Selbstbild mit dem eigenen, so beweist das eine gute Eigenwahrnehmung des Mitarbeiters (vorausgesetzt der Vorgesetzte kann ihn korrekt einschätzen). Außerdem dürfte es bedeuten, dass hier aus beiden Sichtweisen objektiv beurteilt wurde. Fängt der Vorgesetzte hingen als erstes an, seine Einschätzung darzulegen, so kann dies die Aussage des Mitarbeiters beeinflussen (umgekehrt halte ich dies für weniger realistisch). Beispielsweise wird ein Mitarbeiter sicherlich nicht ein Verhalten kritisch beäugen, welches zuvor vom Vorgesetzten gelobt wurde.

Ein weiterer Vorteil ist, dass der Vorgesetzte ggf. nur noch Punkte ergänzen muss, sodass er – so wie es eigentlich ideal ist – lediglich das Gespräch passiv lenkt und ein Groß vom Mitarbeiter selbst kommt. Dadurch gibt es weniger Unterbrechungen, schließlich sind Mitarbeiter immer in Versuchung direkt zu widersprechen, schließlich wirken Kritikpunkte – und sei der Sachverhalt noch so euphemistisch ausgedrückt – immer provozierend.

Bei Zielvereinbarungen (als weiteres Teilgespräch) werden sich Mitarbeiter eher mit Zielen identifizieren, welche sie selbst hervorgebracht haben (die man natürlich subtil noch den eigenen Vorstellungen angleicht), als denen, die ihnen “aufgebrummt” wurden.

Wer genauer darüber nachdenkt, wird noch auf einige weitere Vorzüge dieses Vorgehens kommen. An dieser Stelle lasse ich es aber darauf beruhen. Schreibt mit doch bitte einen Kommentar, wenn ihr anderer Meinung seid!

Strategy Pattern mit IoC sauber implementiert

Ein kurzer Hinweis vorab: Den Inhalt des Blogeintrags habe ich auch in einem Webcast zusammengefasst. Das Video gibt es auf YouTube. Den Code findet ihr hier.

In meinem letzten Blogeintrag habe ich das Strategy Pattern in der Praxis gezeigt. Primär gab es noch einen Smell, welchen ich erwähnt hatte: Das Open Closed Principle ist damit noch nicht 100%ig eingehalten und an einer Stelle heble ich mein IoC Konzept aus. Das passiert genau hier:

   1: public StateHandler(IClock clock, IBuildDefaultProposalsValues defaultValues)

   2: {

   3:     Handler = new Dictionary<SelloutStates, ICreateOrderProposal>

   4:               {

   5:                   {SelloutStates.Oversupply, null},

   6:                   {SelloutStates.Predicted, new PredictedGap(defaultValues)},

   7:                   {SelloutStates.Urgent, new UrgentGap(defaultValues, clock)},

   8:                   {SelloutStates.AppointmentWarnings, new AppointmentWarning(defaultValues, clock)},

   9:                   {SelloutStates.Unknown, null},

  10:                   {SelloutStates.Verify, new NoForecastPossible(defaultValues)},

  11:                   {SelloutStates.Ok, new UncomplicatedAppointment(defaultValues, clock)}

  12:               };

  13: }

Zum einen müsste ich die Klasse immer anpassen, wenn ich einen weiteren Status aufnehmen möchte. Zum anderen erzeuge ich mir Instanzen von Klassen, welche ich nicht über den Container erhalten habe, sprich ich hole mir die Abhängigkeiten selbst, statt mir diese gemäß Inversion of Control Principle zuweisen zu lassen. Das wäre zwar möglich gewesen, allerdings würde der Konstruktor dadurch erheblich aufblähen, weil ich pro Status eine Implementierung reinreichen müssten. Dieses Problem könnte ich über Service Location lösen, d.h. ich lasse mir lediglich den Container reinreichen und mache die Auflösung intern. Für mich persönlich auch keine schöne Lösung (Hinweis: Dafür müsste man den Container in sich selbst registrieren…).

Ob nun saubere Dependency Injection mit aufgeblähtem Konstruktor oder Service Location, in jedem Fall bliebe das Problem, dass ich jedes Mal im Container eine weitere Registrierung für einen neuen Status durchführen müsste.

Daraufhin kamen Rückfragen, wie dies am besten zu lösen sei. Das soll Thema dieses Blogeintrags und des dazu passenden Webcasts sein, v.a. weil im Netz auch nur selten saubere Implementierungen anzutreffen sind, die alle Prinzipien einhalten.

Als erstes wird der obere Code gänzlich entfernt, da dieser nicht mehr benötigt wird. Hinter dem Code steckte eigentlich das Factory Pattern. Ich lasse mir durch die Factory (abhängig vom Status) das entsprechende Objekt erzeugen und arbeite dann mit diesem weiter. Castle.Windsor als IoC Container bietet uns hierfür sogenannte interface-based factories an.

Anmerkung: Der folgende Code basiert nicht mehr auf dem bisherigen, welchen ich im vorherigen Blogeintrag verwendet habe. Im Webcast ist dazu alles erläutert und ich habe das Projekt unter Github zur Verfügung gestellt.

   1: yield return Component

   2:     .For<IchVermittleVorschlagsrechner>()

   3:     .AsFactory(c => c.SelectedWith(new VorschlagsrechnerVermittler()));

Wie man sieht, muss man lediglich das Factory-Interface, welches man zuvor selbst ausimplementiert hatte, angeben und im Anschluss ‘AsFactory’ anhängen. Als Parameter übergebe ich den Verweis auf eine Logik, welche die Factory später intern verwendet, um mir das korrekte Objekt (den korrekten Service) zurückzuliefern. Das Bedeutet, dass “new VorschlagsrechnerVermittler” der Factory, wenn auf ihr ein Aufruf stattfindet, sagen muss, was sie zurückgeben soll. Es folgt die Implementierung:

   1: public class VorschlagsrechnerVermittler : DefaultTypedFactoryComponentSelector

   2: {

   3:     protected override string GetComponentName(MethodInfo method, object[] arguments)

   4:     {

   5:         if (method.Name == "Für" && arguments.Length == 1 && arguments[0] is Bestandsstatus)

   6:         {

   7:             var status = arguments[0].ToString();

   8:             //von mir frei gewählte Konvention wie die Komponente im Container heißt

   9:             return string.Format("BerechnerFürArtikelstatus{0}", status);

  10:         }

  11:         return base.GetComponentName(method, arguments);

  12:     }

  13: }

Dieser Code macht nun genau das, was ich vorher explizit im Dictionary definiert habe, allerdings anhand einer Konvention. Die Methode in Zeile 3 liefert als String den Namen der Komponente zurück basieren auf dem Namen des Status, also z.B. ergibt sich für den Status “Ok” der Komponentenname “BerechnerFürArtikelstatusOk”.

Nun fehlt lediglich noch eine kleine Anpassung für den IoC Container. Dieser weiß bisher nichts von einer Komponente “BerechnerFürArtikelstatusOk”. Eine Möglichkeit wäre, dass ich – wie bereits eingangs erwähnt – für jeden Status die Ausprägung im Container registriere, also in diesem Fall beispielsweise so:

   1: yield return Component.For<IchErrechneArtikelZukaufsvorschlag>()

   2:     .ImplementedBy<Ok>()

   3:     .Named("BerechnerFürArtikelstatusOk")

   4:     .LifestyleTransient();

Das widerspricht immer noch dem OCP, sodass ich es wie folgt löse:

   1: yield return AllTypes.FromThisAssembly()

   2:     .BasedOn<IchErrechneArtikelZukaufsvorschlag>()

   3:     .Configure(a => a.Named(string.Format("BerechnerFürArtikelstatus{0}",

   4:         a.Implementation.UnderlyingSystemType.Name)))

   5:     .Configure(a => a.LifestyleTransient());

Zunächst hole ich mir alle Klassen aus der aktuellen Assembly, welche auf “IchErrechneArtikelZukaufsvorschlag” basieren, also alle meinen konkreten Status-Implementierungen. Im Anschluss sage ich noch, welchen Name diese Komponenten im Container bekommen sollen. Hier steht die selbe Konvention wie in dem Code Sample  zuvor. Der Vollständigkeit halber sei erwähnt, dass ich hier gegen das Don’t Repeat Yourself Principle verstoße. Dies soll lediglich der Vereinfachung im Beispiel dienen.

Ab jetzt muss ich, wenn ein weiterer Status hinzu kommt, lediglich eine Implementierung für diesen machen. Bestehender Code muss nicht mehr angefasst werden.

Die Sache mit den Entscheidern – Lean Management

Im ersten Teil habe ich mich mit Pair Programming beschäftigt. Auf dem .NET Open Space Süd kam natürlich auch das Dauerbrennerthema agiles Projektmanagement auf. Deshalb geht es in diesem Artikel genau darum, d.h. nicht um Scrum als eine Ausprägung davon, sondern um die Konzepte dahinter und wie sich diese den verantwortlichen Stellen verkaufen lassen.

Persönlich denke ich, dass sich die Ideen dahinter auch zum großen Teil umsetzen lassen, ohne dass der Prozess vollständig implementiert werden muss. Das könnte die Basis für eine offene Diskussion sein, denn viele Projektmanager (PMs) winken bereits ab, wenn sie Begriffe wie Agilität und Scrum hören.

Fangen wir doch mit dem Work In Progress (WIP) an: Statt an 10 Projekten gleichzeitig zu arbeiten, die erst nach 10 Monaten einsatzbereit sind, ist es betriebswirtschaftlich gesehen immer sinnvoller, ein Projekt nach dem anderen zu realisieren. Bündelt man die Arbeitskraft, wäre je ein Projekt nach einem Monat fertig (vereinfachte Rechnung…), sodass beispielsweise 3 Module nach 3 Monaten effektiv eingesetzt werden und Kosten eingespart bzw. Gewinne maximiert werden könnten. Diese Argumentation dürfte einfach zu gewinnen sein, wenn denn der PM rudimentäre Kenntnisse im Projektmanagement besitzt.

Bei der Projektplanung wird nicht über die innere Qualität diskutiert, d.h. Debatten wie ‘dann machen Sie es erst einmal Quick and Dirty, damit wir Zeit sparen’ entfallen. Mit der Fachabteilung wird lediglich der Umfang verhandelt, sprich wenn Zeit eingespart werden soll, dann nicht durch schlechteren Code, sondern durch weniger Features. Diese Diskussion könnte schon schwieriger zu gewinnen sein. Wenn der PM über längere Berufserfahrung verfügt, dürfte eine ehrliche Betrachtung der Vergangenheitswerte ihn aber ebenfalls zur Einsicht bringen. In jedem Fall – auch unabhängig von der Praxiserfahrung – können hier Beispiele aus dem privaten Leben fruchten: Wenn das Auto nur provisorisch repariert wird, dann folgt das böse Erwachen meistens früher als später.

Regelmäßige Meetings (alle 1-2 Wochen) ergeben sich allein schon aus der schnellen Entwicklung der geschäftlichen Prozesse. Wer aber auch hier Überzeugungsarbeit leisten muss, der könnte sich von dem PM bzw. der Fachabteilung das Spiel Tic Tac Toe erläutern lassen. Mir scheint es unrealistisch, selbst bei diesem einfachen Szenario, dass immer an alles gedacht wird. Was passiert, wenn ein Spieler gewonnen hat? Soll automatisch ein neues Spiel gestartet werden, soll eine Gewinnmeldung ausgegeben werden, etc.. Hierzu gibt es einen Artikel in der dotnet pro, in welchem besagtes Spiel auseinander genommen und aus diesem Kontext heraus beleuchtet wird. Viele der Fragen tauchen erst im Verlauf der Entwicklung auf, sodass ein großes Meeting, in welchem alles besprochen werden kann, zw. unrealistisch bis unmöglich schwankt.

Planungssicherheit ist ein Schlagwort, welches im Kontext des Wasserfallmodells völlig fehl am Platze ist. Welches Projekt, das auf 2, 5 oder 10 Jahre angelegt war, konnte tatsächlich die Rahmenplanung (Kosten, Zeit) einhalten. Die Zahl dürfte gegen 0 gehen. Vergangenheitsbetrachtungen dürften hier auch schnell Aufschluss geben. Es existieren keine Referenzprojekte? In der Tagesschau hört man wöchentlich von solchen, sei es nun der Bau eines neuen Flughafens oder die Einführung eines Mautsystems. Durch die kurzen Iterationen erreicht man schnell (meistens innerhalb von 8-12 Wochen) einen guten Eindruck dafür, was innerhalb von 2 Wochen erreichbar ist. Was scheint nun plausibler? Eine Planung, die auf Vergangenheitswerten beruht und die vom Kleinen ins Große rechnet oder der umgekehrte Weg, bei welchem 2 Jahre angesetzt werden und dann muss das Projekt abgeschlossen sein? Lieber den Spatz in der Hand oder die Taube auf dem Dach?

Zusammenfassend lässt sich sagen, dass es vielleicht langfristig mehr von Erfolg gekrönt ist, wenn sukzessive einzelne Punkte aus dem agilen Projektmanagement integriert werden, ohne diese vor dem PM als agil zu deklarieren. Wenn dann sowieso bereits zu 50% nach der entsprechenden Ideologie gehandelt wird, wäre ein Scrum Buch vielleicht das passende Geburtstagsgeschenk für den PM. Beim Lesen sollte es ihm/ihr dann wie Schuppen aus den Haaren fallen. Idealerweise hält der PM dann eure Idee noch für seine eigene…

Strategy Pattern in der Praxis

Heute gibt es von mir einen kleinen Bericht aus der Praxis. Ich habe zunächst folgenden Code geschrieben, welchen ich nun, nachdem die Logik fertig ist, überarbeite.

Ausgangssituation: Anhand diverser Eigenschaften eines Artikels wird dessen Status ermittelt. Abhängig vom Status soll eine Aktion ausgelöst werden. Im vorliegenden Fall ist dies so gelöst, dass eine Switch-Anweisung anhand des Status in den entsprechenden Zweig springt (vgl. ab Zeile 3). In dem jeweiligen Zweig wird eine dedizierte Methode innerhalb der Klasse aufgerufen.

   1: var state = Decide(entry, folder);

   2:  

   3: switch (state)

   4: {

   5:     case SelloutStates.Urgent:

   6:         CreateUrgentGap(result, entry, folder);

   7:         break;

   8:  

   9:     case SelloutStates.Predicted:

  10:         CreatePredictedGap(result,entry,folder);

  11:         break;

  12:  

  13:     case SelloutStates.Verify:

  14:         ForecastNotPossible(result, entry, folder);

  15:         break;

  16:     

  17:     case SelloutStates.AppointmentWarnings:

  18:         CreateAppointmentWarning(result, entry, folder);

  19:         break;

  20:  

  21:     case SelloutStates.Ok:

  22:         CreateUncomplicatedAppointment(result, entry, folder);

  23:         break;

  24:  

  25:     case SelloutStates.Unknown:

  26:         throw new ApplicationException(string.Format("Unbekannter Status für Artikel '{0}'", entry.Article.NumberFormatted));

  27:  

  28:     default:

  29:         throw new ApplicationException(string.Format("Keine Logik zur Verarbeitung des Status für Artikel '{0}'", entry.Article.NumberFormatted));

  30: }

  31:  

  32: SelloutStates Decide(OrderProposalArticleDataEntry entry, OrderProposalFolder folder)

  33: {

  34:     if (folder == null)

  35:         throw new ApplicationException(String.Format("Der Artikel '{0}' war keiner Mappe zugeordnet", entry.Article.NumberFormatted));

  36:  

  37:     if (!entry.AverageUsage.HasValue || !entry.SelloutDate.HasValue)

  38:         return SelloutStates.Verify;

  39:  

  40:     if (!entry.NextIntakeDateAfterSellout.HasValue)

  41:         throw new ApplicationException(String.Format("Bei Artikel '{0}' war kein nächster Wareineingang gesetzt, obwohl ein Leerverkaufsdatum existiert",

  42:             entry.Article.NumberFormatted));

  43:  

  44:     if (entry.SelloutDate < _clock.Now)

  45:         return SelloutStates.Urgent;

  46:  

  47:  

  48:  

  49:     if (entry.SelloutDate < entry.NextIntakeDateAfterSellout)

  50:     {

  51:         var nextPossibleIntake = _clock.Now.AddDays(folder.HandlingTimeInDays).AddDays(folder.DeliveryPeriodInDays);

  52:         var orderInTimeIsPossible = entry.SelloutDate.Value.TimeSpanIgnoringTimeOfDay(nextPossibleIntake).Days >= 0;

  53:  

  54:         return orderInTimeIsPossible ? SelloutStates.AppointmentWarnings : SelloutStates.Predicted;

  55:     }

  56:  

  57:     return SelloutStates.Ok;

  58: }

Ganz offensichtlich wird hier gegen das Open-Closed-Principle und Single-Responsibility-Principle verstoßen, denn wenn ich nun einen weiteren Status aufnehmen möchte, müsste ich das Switch-Statement erweitern und gleichzeitig noch eine weitere Methode einfügen. Übersichtlich sieht das Ganze auch nicht aus.

Deshalb habe ich ein Interface erstellt:

   1: public interface ICreateOrderProposal

   2: {

   3:     void CreateWith(OrderProposals result, OrderProposalArticleDataEntry entry, OrderProposalFolder folder);

   4: }

Für jeden Status habe ich sodann eine Klasse erzeugt, welche das Interface implementiert. Hier ein Beispiel:

   1: public class NoForecastPossible : ICreateOrderProposal

   2: {

   3:     readonly IBuildDefaultProposalsValues _defaultValues;

   4:  

   5:     public NoForecastPossible(IBuildDefaultProposalsValues defaultValues)

   6:     {

   7:         _defaultValues = defaultValues;

   8:     }

   9:  

  10:     public void CreateWith(OrderProposals result, OrderProposalArticleDataEntry entry, OrderProposalFolder folder)

  11:     {

  12:         var appointment = _defaultValues.ForAppointment(entry, folder);

  13:  

  14:         appointment.CalculatedOrderInDays = null;

  15:         appointment.Status = SelloutStates.Verify;

  16:  

  17:         result.Appointments.Add(appointment);

  18:     }

  19: }

 

Zu guter Letzt habe ich mir noch eine Implementierung geschrieben, die in einem Dictionary die Zuordnung von State zu entsprechender Programmlogik hält (ebenfalls als Interface abstrahiert!):

   1: public class StateHandler : IAllocateHandlerToState

   2: {

   3:     private Dictionary<SelloutStates, ICreateOrderProposal> Handler { get; set; }

   4:  

   5:  

   6:     public StateHandler(IClock clock, IBuildDefaultProposalsValues defaultValues)

   7:     {

   8:         Handler = new Dictionary<SelloutStates, ICreateOrderProposal>

   9:                   {

  10:                       {SelloutStates.Oversupply, null},

  11:                       {SelloutStates.Predicted, new PredictedGap(defaultValues)},

  12:                       {SelloutStates.Urgent, new UrgentGap(defaultValues)},

  13:                       {SelloutStates.AppointmentWarnings, new AppointmentWarning(defaultValues, clock)},

  14:                       {SelloutStates.Unknown, null},

  15:                       {SelloutStates.Verify, new NoForecastPossible(defaultValues)},

  16:                       {SelloutStates.Ok, new UncomplicatedAppointment(defaultValues, clock)}

  17:                   };

  18:     }

  19:  

  20:     

  21:     public ICreateOrderProposal Handle(SelloutStates state)

  22:     {

  23:         return Handler[state];

  24:     }

  25: }

Anmerkung: Wie ihr seht verwende ich eine IClock. Das liegt daran, dass ich inzwischen überall im Code statt DateTime.Now immer auf eine Implementierung von IClock zugreife, um Unit Tests zu ermöglichen, die Datumsangaben prüfen.

 

Das Ergebnis ist, dass ich nur noch einen Zweizeiler habe:

   1: var state = _orderProposalState.Evaluate(entry, folder);

   2: _orderProposalFactory.Handle(state).CreateWith(result,entry,folder);

Falls ihr euch wundert, wo die Methode ‘decide’ abgeblieben ist: Diese habe ich im gleichen Zug ebenfalls in eine eigene Klasse extrahiert. Die Implementierung dazu erhalte ich über den Konstruktor vom IoC. Die Variable ‘_orderProposalState’ enthält nun diese Logik.

Vorteil? Ganz offensichtlich ist die Klasse übersichtlicher geworden und zwar erheblich. Natürlich könnte man jetzt argumentieren, dass ich die Logik auf weitere Klassen verteilt habe (was neben dem SRP übrigens auch dem Separation of concerns Prinzip entspricht). Das ist natürlich richtig, aber in dieser Klasse sehe ich auf Anhieb den Zusammenhang: Ich ermittle einen Status eines Artikels. Im Anschluss reagiere ich in einer speziell dafür vorgesehenen Geschäftslogik. Wenn ich nun wissen will, wie der Status ermittelt wird, dann gehe ich in die dafür zuständige Klasse. Will ich hingegen wissen, wie ein Artikel mit diesem speziellen Status verarbeitet wird, gehe ich in die dedizierte Klasse. Will ich das Ganze erweitern, dann baue ich einfach einen weiteren entsprechenden Handler. Bestehender Code muss nicht angefasst werden (Ausnahme: Die Klasse StateHandler, aber auch dies könnte man anders lösen!). Und zu guter Letzt gestalten sich die Tests deutlich einfacher.

SharePoint Suche

Wenn die SharePoint Suche bei manchen Anwendern etwas anzeigt und bei anderen nicht, so könnte das Problem darin bestehen, dass das entsprechende Domänen-Objekt nicht korrekt konfiguriert ist. Im vorliegenden Fall war es so, dass die Kollegen aus dem Marketing keine Suchergebnisse im Wiki angezeigt bekommen haben, wir in der IT hingegen schon. Die Lösung stand in diesem Blogeintrag.

<<Lt. Doku muss man dem Search-Dienst User im Active Directory unter dem Reiter Sicherheit – bei Authentifizierte Benutzer das Recht "Lesen" zuweißen.>>

Inzwischen läuft alles problemlos…

Meine tägliche Portion Git

Heute habe ich auf Grund einer Unachtsamkeit einen falschen Merge getätigt. Die Folge war, dass mein Stand nach dem Rebase fehlte. Konkret kann euch dies passieren, wenn ihr beispielsweise an einer Klasse entwickelt, die Änderungen eincheckt und euch dann das aktuelle Repository über einen Pull zieht. Hat nun ein anderer Entwickler ebenfalls etwas an dieser Datei geändert, so schlägt das Mergen fehl und ihr seid in eurem Branch abgezweigt. In der Regel löst man dies, indem man manuell mergt. Danach führt man über “git rebase –continue” das Zusammenführen des Remote Repository und eures lokalen Repository zu Ende. Stell ihr nun fest, dass ihr falsch gemergt habt, könnt ihr nicht ohne weiteres eure Datei wiederherstellen.

In dem Falle ruft ihr “git reflog” auf. In dem Falle seht ihr alle je getätigten Commits.

image

Nun könnt ihr über “git reset –hard SHA” auf den commit zurück, den ihr vor dem Rebasing hattet. SHA entspricht dabei dem SHA eures Commits. Danach könnt ihr erneut pullen und korrekt mergen.

Die Sache mit den Entscheidern – Pair Programming

Vergangenes Wochenende war wieder .NET Open Space Süd in Karlsruhe. Es zeichnete sich das gleiche Bild ab wie bereits in Leipzig 2011: Ein steigender Teil der Entwickler ist unzufrieden. Als Hauptursache meine ich folgende Punkte identifiziert zu haben:

  • Innovationen werden durch den CIO/CTO gänzlich abgelehnt
  • Neue Wege werden von der GL nur halb mitgegangen, solange sie noch “angenehm” zu gehen sind
  • Frische Ansätze werden vorsätzlich sabotiert, z.T. durch das Team

Dementsprechend trifft das dann die sogenannten “schöpferischen Zerstörer” (Buchreferenz fehlt mir aktuell), d.h. kreative, innovative Menschen, die den Status Quo und all seine negativen Mitbringsel aufbrechen wollen.

Betrachtet man die letzten Jahre, so hat sich vieles getan. Zum einen im Prozess- und Projektmanagement, als auch in den dazu passenden Werkzeugen. Zu nennen wäre die Ausrichtung am Lean Management, z.B. in Form von Scrum, oder Continuous Integration (bzw. Continuous Deployment) durch einen Build Server. Clean Code – heutzutage in aller Munde – besagt nicht viel mehr, als dass man sich ständig weiterbilden und Softwareentwicklung als Handwerkskunst verstehen muss.

Stand heute stehen viele Vorgesetzte respektive Entscheider – sei es nun der IT Abteilungsleiter oder Geschäftsführer -  dieser Bewegung entweder skeptisch oder gänzlich ablehnend gegenüber. Warum auch CIOs eine derartige Haltung einnehmen, ist für mich bis dato nicht nachzuvollziehen. Schließlich sind die Stellenanforderungen an diese Position primär Kreativität, innovatives und prozessorientiertes Denken, sowie ausgeprägtes Business Alignment.

Deshalb möchte ich in den nächsten Wochen hin und wieder Punkte aufgreifen, welche typischerweise von Entscheidern mit in der Regel altbackenen Argumenten abgelehnt werden. Heute befasse ich mich mit Pair Programming:

Hier ist natürlich als Gegenargument zu hören, dass es betriebswirtschaftlich keinen Sinn macht, wenn zwei Personen an der gleichen Aufgabe arbeiten. Genauer gesagt würde ja nur einer arbeiten und der andere schaut dabei zu. Aber gerade Pair Programming ist ein Musterbeispiel dafür, wie falsch solche Aussagen von entsprechenden Stellen sein können!

Inselwissen ist sicherlich in jeder Firma ein Problem – teilweise vielleicht so groß, dass die Geschäftsleitung gar keine Vorstellung davon hat! Wenn immer zwei Personen an einem Stück Code schreiben, ist dem von Anfang an Einhalt geboten. Wird beim Pair Programming auch noch regelmäßig durchgewechselt, was sich für Teams ab einer Größe von 4 Personen immer anbietet, so ergeben sich weitere Synergieeffekte, da z.B. das Gesamtverständnis für das System gefördert und Doppelentwicklungen vermieden werden.

Als nächster Punkt wäre anzumerken, dass dadurch quasi eine kostenfreie Schulung stattfindet. Nach meiner Erfahrung bietet selbst der einfachste Code Gelegenheit für neues Detailwissen. Als Beispiel diene das Schlüsselwort checked für die Addition zweier Integer-Werte. Darüber hinaus hat jeder Developer sein Spezialgebiet, in welchem er dem Kollegen Wissen vermitteln kann.

Und noch ein Argument darf aus betriebswirtschaftlicher Sicht nicht fehlen: Der Code wird “besser”, d.h. Arbeitszeit für Refactoring, Neuprogrammierung und Nachbesserung wird eingespart. Fehler die früh aufgedeckt werden, sparen bare Münze! Ein toller Spruch hierzu kam am Open Space ebenfalls: Für das Programmieren wird eine Gehirnhälfte im Menschen beansprucht, d.h. wenn zwei Entwickler am selben Problem arbeiten, hat man ein vollständiges Gehirn, welches sich dem Problem annimmt.

3 wertvolle Tipps gegen Viren und Trojaner

Auf Grund der Tatsache, dass ich inzwischen wöchentlich um Hilfe bei Virenbefall befragt werde, möchte ich hier jetzt Maßnahmen zur Prophylaxe bereitstellen. Aus Zeitgründen stelle ich lediglich die Links ohne größere Anleitungen vor!

Browser:

Idealerweise verwendet ihr zum Surfen im Internet folgenden Browser: BitBox. Es handelt sich dabei um eine modifizierte Firefox-Version. Für Online Banking würde ich euch sogar ausschließlich diesen Browser empfehlen (mache zumindest ich so). Achtet bei der Installation darauf, dass ihr BitBox als Standardbrowser definiert. Mit diesem Tipp könnt ihr am meisten erreichen!

Wenn ihr das nicht wollt, so installiert euch Plugins wie NoScript, WOT und  Adblock. Alle 3 Plugins gibt es auch für Chrome. Verwendet im Falle von IE und Firefox auch immer die aktuellste Flash Version (Chrome bringt eine eigene Version mit und aktualisiert diese selbstständig). Haltet darüber hinaus auch euren Browser immer aktuell, sprich installiert immer die neuste Version. Chrome erledigt dies selbstständig, Firefox fragt euch regelmäßig.

 

Windows:

Nutzt Windows 7 oder Vista und vermeidet XP. Aber nun egal, was ihr einsetzt, aktiviert immer die Automatischen Updates und spielt diese sofort ein.

 

Virenscanner:

Nutzt einen aktuellen Virenscanner und achtet darauf, dass dieser immer aktiviert ist und die aktuellen Updates eingespielt hat.

 

Es gibt noch wesentlich mehr Möglichkeiten zu schützen, aber diese sind essentiell und relativ einfach umzusetzen. Beim Surfen noch den Verstand einschalten und nicht auf alles klicken, was sich bewegt bzw. fragwürdig aussieht, dann solltet ihr unbeschadet durch das Internet kommen.

 

Weiterführende Links:

Selbsttest – Bin ich ein Workaholic

10 Punkte zum Erkennen, ob ihr zu viel arbeitet:

  1. Wenn die Kollegen dich morgens fragen, ob du noch oder schon wieder da bist
  2. Wenn dich dein Freundeskreis immer zuerst im Büro anruft
  3. Wenn du einen eigenen Kühlschrank zugewiesen bekommst
  4. Wenn die Kaffeemaschine Tränen kriegt, sobald du ihr entgegenläufst
  5. Wenn deine Partnerin dir Meeting-Anfragen schicken muss
  6. Wenn du zuhause die gleichen Möbel stehen hast wie im Büro
  7. Wenn du mehr Kleider zum Wechseln im Büro hast, als zuhause
  8. Wenn du eine Schlafcouch im Büro stehen hast
  9. Wenn deine Kollegen dich fragen, ob du eigentlich Miete bezahlst
  10. Wenn der Chef dann tatsächlich Miete verlangt
%d Bloggern gefällt das: