Archiv für den Monat September 2011

Using an IoC-Container right

I noticed that some people don’t use their IoC-Container in the manner they should to. They inject the container into their objects like this:

   1: public class Foo : IFoo

   2: {

   3:     private IContainer _container;

   4:  

   5:     public Foo(IContainer container) {

   6:         _container = container;

   7:     }

   8:  

   9:     public Boo GetBooForFoo(int id) {

  10:         var boo = _container.Resolve<IMyService>().GetBooById(id);

  11:         return boo;

  12:     }

  13: }

A friend of mine (Web Developer) uses the same approach (not with an IoC but an array) in PHP: He injects an array that contains every dependency. When i asked him why he is doing this that way, he told me that he doesn’t want his API to change when he needs more dependencies.

So why is this a bad decision:

  • Fail Fast Principle: If the requested service IMyService in line 10 is not found, it will raise an Exception (for example an ComponentNotFoundException). In this scenario that’s no fracture of the leg but what if you would have executed some important changes before? You shouldn’t be able call a method without having the a valid starting point. It’s much better and cleaner to get an exception when you instantiating the object Foo.
  • Keep in mind why you are using an container: You want to implement the Inversion of Control principle. It’s not your call that should be in control, it’s your container. It’s paradox to use an IoC-Container when you develop your code to annul the basic principle behind. Another point is that you have a hard coded dependency to a specific container implementation so you’re not able to switch you IoC-Container.
  • And my last consideration is about the benefit that you’re api won’t change: Don’t hide dependencies! If you’re not the only developer that works with that code, you will get big problems because you change the components behaviour without getting errors. A developer that uses this component is wondering why his program is not working correctly any longer. Or – and that would be really upsetting – the calling component works in some cases and in some cases not for example if line 10 would be in a switch statement.

Too make a long story short: Here’s my approach

   1: public class Foo : IFoo

   2: {

   3:     private IMyService _myService;

   4:     

   5:     public Foo(IMyService myService) {

   6:         //you might want to do a null check

   7:         //what's not necessary if you unit tested your IoC right

   8:         _myService = myService

   9:     }

  10:  

  11:     //you should know what to do now

  12: }

Werbung

Fakes, Mocks, statischer Code und fehlende Interfaces

Kürzlich habe ich meinen Kollegen aus der PHP Entwicklung gezeigt, wie man mit statischem Code aus dem Framework umgeht, zu dem es keine Interfaces gibt. Heute kam auf der User Group Karlsruhe nochmals das Thema in einem Dialog auf sodass ich das Beispiel hier publizieren will.

Dazu dient mir die Console-Klasse aus dem .NET Framework. Ich könnte jetzt auf die häufig verwendete WriteLine-Methode eingehen, allerdings will ich die Aufgabe ein wenig erschweren, indem ich die ReadKey-Methode mocken bzw. faken will. Damit haben wir auch gleich das Thema User Interaktion abgedeckt.

Zunächst noch eine Klarstellung: Von Fakes spricht man, wenn man Dummy-Implementierungen selbst schreibt. Just in diesem Moment habe ich Dr. House geschaut und da kam der Ausspruch “das war bloß gefakt” vor. Eine gute Eselbrücke, wie ich finde, da man für einen Fake eben aktiv werden muss. Mocking bezeichnet das automatische Erstellen von Fakes anhand von Interfaces dynamisch zur Laufzeit. Die dazu benötigten Proxies werden können mit Mocking Frameworks erzeugt werden. Beide Verfahren werde ich zeigen.

Schauen wir uns den eigentlichen Code an, den wir dann verbessern, um ihn zu testen:

   1: public void Process()

   2: {

   3:     var userChoice = Console.ReadKey();

   4:     switch (userChoice.Key)

   5:     {

   6:         case ConsoleKey.S:

   7:             //Logik A ausführen

   8:             break;

   9:  

  10:         default:

  11:             //Logik B ausführen

  12:             break;

  13:     }

  14: }

Wie können wir das testen? Ideal wäre, wenn es ein Interface für die Console Klasse gäbe. Gibt es aber nicht. Also erstellen wir unser eigenes:

   1: public interface IConsoleHelper

   2: {

   3:     ConsoleKeyInfo ReadKey();

   4: }

Die Implementierung für unser eigentliches Programm ist das nichts anderes als ein Wrapper für die ursprüngliche Logik:

   1: public class ConsoleHelper : IConsoleHelper

   2: {

   3:     public ConsoleKeyInfo ReadKey()

   4:     {

   5:         return Console.ReadKey();

   6:     }

   7: }

So weit so gut. Nun muss das ursprüngliche Programm diese Abhängigkeit reingereicht bekommen. Wie, das ist euch überlassen. Entweder ihr übergebt die Implementierung per  Constructor Injection oder per Method Injection. Ich halte es immer so, dass alle für den eigentlich Logikablauf essentielle Abhängigkeiten über den Konstruktor reingereicht und alle optionalen Abhängigkeiten (wie einen Logger) über eine Methode (z.B. SetLogger(ILogger logger)) injiziert werden. Egal wie ihr das implementiert, innerhalb des Programms gibt es dann die Instanzvariable _consoleHelper vom Typ IConsoleHelper. Der Code sieht dann wie folgt aus:

   1: public void Process()

   2: {

   3:     var userChoice = _consoleHelper.ReadKey(); //<- Hier liegt der Unterschied

   4:     switch (userChoice.Key)

   5:     {

   6:         case ConsoleKey.S:

   7:             //Logik A ausführen

   8:             break;

   9:  

  10:         default:

  11:             //Logik B ausführen

  12:             break;

  13:     }

  14: }

 

Nun zum Testen. Euer Unit Test müsste nun prüfen, o bei der Eingabe von S Logik A und bei sonstigen Eingaben Logik B ausgeführt wird.

Zuerst die Möglichkeit mit einem selbstgeschriebenen Fake, den ich zum Testen des ersten Falls, nämlich der Eingabe von S, nehme:

   1: /// <summary>

   2: /// Eigene Fake-Implementierung zum faken von Konsoleneingaben

   3: /// </summary>

   4: public class ConsoleFake : IConsoleHelper

   5: {

   6:     public ConsoleKeyInfo ReadKey()

   7:     {

   8:         return new ConsoleKeyInfo('s', ConsoleKey.S,false,false,false);

   9:     }

  10: }

 

Und hier die Implementierung eines Mocks mit dem Framework Fake It Easy:

   1: var consoleFake = A.Fake<IConsoleHelper>();

   2: A.CallTo(() => consoleFake.ReadKey())

   3:        .Returns(new ConsoleKeyInfo(

   4:             'a', ConsoleKey.A, false, false, false)

   5:         );

 

Schaut euch auch den Artikel über das Mocken von DateTime.Now an.

Gehaltsverhandlungen – Teil 3

Da die Resonanz auf den letzten Artikel so groß war und ich gebeten wurde weiterführende Links oder Buchempfehlungen zu geben, habe ich in den vergangenen Tagen einige Links gesammelt. Außerdem habe ich euch ein paar sinnvolle Twitter Accounts aufgelistet, die immer wieder top aktuelle Infos zu den Themen Gehälter, Karriere und Jobs zwitschern. Über das Tag Gehalt findet ihr meine zwei früheren Einträge.

Twitterer:

 

Artikel auf Gehalt.de:

 

Sonstiges:

%d Bloggern gefällt das: