Archiv der Kategorie: Architecture

Bessere Enumerations in NET

Ist euch der Smell von typischen Enumerations auch schon in die Nase gestiegen? In diesem Webcast zeige ich eine Alternative zu den typischen Enums in NET. Damit können das Open Closed Principle und Separation of Concerns besser umgesetzt werden, was meiner Meinung nach zu einer höheren Kohäsion führt.

 

Weiterführende Links:

 

Wie haltet ihr es mit Enums? Arbeitet ihr schon auf diese Weise? Wollt ihr mehr Webcasts zu Clean Code?

Advertisements

Flexibles Bootstrapping durch Composition

In diesem Webcast zeige ich unseren Kompositions-Ansatz für das Bootstrapping. Die Interfaces sind schmal, die Implementierungen überschaubar, das Ganze ist flexibel und lässt sich gut testen.

Hier der gezeigte Code:

   1: public class BootstrapperContext

   2: {

   3:     public BootstrapperContext()

   4:     {

   5:         AppConfig = new ApplicationConfig();

   6:         Container = new WindsorContainer();

   7:     }

   8:  

   9:     public IWindsorContainer Container { get; private set; }

  10:     public ApplicationConfig AppConfig { get; private set; }

  11: }

   1: public interface IAmABootstrapperAction

   2: {

   3:     void Execute(BootstrapperContext context);

   4: }

 

   1: public interface IAmABootstrapperComposition

   2: {

   3:     IEnumerable<IAmABootstrapperAction> Actions { get; }

   4: }

 

   1: public class BootstrapperExecutor

   2: {

   3:     public static void StartupApplication(IAmABootstrapperComposition bootstrapperComposition)

   4:     {

   5:         var exceptionMessage = "Beim Starten der Anwendung ist ein Fehler aufgetreten. Bitte den Support kontaktieren.\n\n";

   6:  

   7:         if (bootstrapperComposition.Actions == null || !bootstrapperComposition.Actions.Any())

   8:         {

   9:             throw new BootstrapperException(exceptionMessage, new ArgumentOutOfRangeException("Auf dem Bootstrapper waren keine Actions definiert"));

  10:         }

  11:  

  12:         var context = new BootstrapperContext();

  13:  

  14:         var time = TimedAction.Run(() =>

  15:                                    {

  16:                                        foreach (var action in bootstrapperComposition.Actions)

  17:                                        {

  18:                                            var actionName = action.GetType().Name;

  19:                                            SiAuto.Main.LogMessage(string.Format("{0} gestartet", actionName));

  20:  

  21:                                            var timeTaken = TimedAction.Run(() => { ExecuteAction(action, context, exceptionMessage); });

  22:  

  23:                                            SiAuto.Main.LogMessage(string.Format("{0} in {1} erfolgreich durchgeführt",

  24:                                                                                 actionName,

  25:                                                                                 timeTaken.Format())

  26:                                                );

  27:                                        }

  28:                                    });

  29:     }

  30:  

  31:     private static void ExecuteAction(IAmABootstrapperAction action, BootstrapperContext context, string exceptionMessage)

  32:     {

  33:         try

  34:         {

  35:             action.Execute(context);

  36:         }

  37:         catch (Exception ex)

  38:         {

  39:             SiAuto.Main.LogException(string.Format("Fehler beim Bootstrapping: {0}", ex.GetFullExceptionMessage()), ex);

  40:             throw new BootstrapperException(string.Format("{0}{1}", exceptionMessage, ex.GetFullExceptionMessage()), ex);

  41:         }

  42:     }

  43: }

 

Welchen Ansatz verfolgt ihr?

Fragen oder Feedback könnt ihr mir gerne als Kommentar hinterlassen.

Lazy Loading mit IoC

Update vom 04.09.2013: Beachtet bitte die Kommentare. Das Lazy-Feature kann auch erhebliche Performance-Einbußen zur Folge haben. Es kommt darauf, was der Konstruktur des Lazy-Objekts noch an Abhängigkeiten hat und welche Logik in selbigem noch ausgeführt wird.

In diesem Webcast zeige ich welche Möglichkeiten Castle.Windsor für das Lazy Loading von Abhängigkeiten bietet. Das Feature wurde in Version 3 eingeführt. Weiterführenden Inhalt welche Performance Gedanken dahinter stecken und wann idealerweise der Graph des Container geladen werden sollte, findet ihr hier und hier.

Für diejenigen, die einen anderen Container nutzen: Falls euer Framework die Funktionalität nicht out-of-the-box mitliefert, so stellt sich eine eigene Lösung nicht als allzu schwierig heraus. In dem oben zuletzt erwähnten Link gibt es dazu ein Code Sample.

Als grobe Richtlinie kann man sich merken:

Das Laden von weiteren Abhängigkeiten wird v.a. dann “teuer”, wenn die Implementierungen in Assemblies liegen, die noch nicht geladen wurden.

TDD as if you meant it

Als Ralf Westphal im Juli in der .NET UserGroup Rhein Neckar eine Session zu TDD as if you meant it hielt, wollten meine Karlsruhe Kollegen und ich uns das nicht entgehen lassen. Neue Denkansätze zu TDD als state-of-the-art Praktik sind für mich persönlich aktuell ein Dauerthema, da ich immer noch Potential nach oben sehe.

Als Vorbereitung las ich die zugehörige Artikelserie aus der dotnet pro. Ich will jetzt nicht das dort Geschriebene kommentieren oder gar hier ausführen, denn als .NET Developer haben hoffentlich die meisten Zugriff auf den Inhalt. Stattdessen hier kurz die Punkte, die für mich nochmal klarer wurden:

 

  • Für TDDaiymi wird eine feststehende API benötigt, d.h. im Vorhinein muss der Contract stehen
  • TDDaiymi hilft dann dabei die Aspekte innerhalb der Klasse zu identifizieren, sprich die innere Struktur wird entwickelt
  • TDDaiymi ist (zeit-)aufwendiger als “klassisches” TDD und bietet sich v.a. bei komplexen, ggf. nicht gänzlich durchdrungenen Problemen an
  • Als Praktik ist es sicherlich für Coding Dojos interessant, da man für saubere Aspekttrennung und implizite Annahmen (die nicht implizit sein sollten) sensibilisiert wird

 

Das Video habe ich nachbearbeitet, um die Ton- und Bildqualität zu steigern, allerdings ist es zugegebenermaßen nicht optimal. Danke an Ralf nochmal für den Vortrag und die Freigabe des Videos. Den Code gibt es ähnlich in der dotnet pro. Wenn jemand schon Erfahrungen mit der Praktik gesammelt hat, dann würde ich mich über Feedback freuen.

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:

TDD 2.0

Ralf Westphal schreibt in seinem Artikel Ab ins Grüne in der dotnet pro Ausgabe 04/2013 über die Probleme mit TDD. Auf den Punkt gebracht, schildert er seinen Eindruck, dass die Fokussierung auf T(est)D(riven) einen Lösungsansatz perpetuiert hat, der D(evelopment) zu wenig bis gar nicht integriert. Will heißen: Durch die Konzentration auf das Schreiben und Lösen der Tests, wird die Analyse- und Lösungsphase fast gänzlich außer Acht gelassen. Deshalb stünden, so seine Meinung, in Coding Dojos am Ende auch nur selten fertige Ergebnisse.

Aus meiner Sicht trifft Ralf damit voll ins Schwarze. Persönlich störte ich mich seit längerer Zeit an diesem Problem. Ich denke sogar, dass das Development der weit schwierigere Teil ist. Test zu schreiben und den Code dafür entsprechend zu präparieren ist eine Art Training wie das Lösen von Gleichungen 2ter Ordnung in der Schule. Je nach Kenntnisstand des Entwicklers werden noch Vereinfachungen oder schnellere Lösungsansätze wie die binomische Formel erkannt. Ein solides Level stellt sich allerdings nach relativ kurzer Zeit ein. Neue Probleme wie Gleichungen vierter Ordnung bedürfen aber der analytische Fähigkeiten.

Deshalb haben wir bei unseren Coding Dojos die Anregungen aufgegriffen und implementiert. Interessanterweise, was ich persönlich als sehr positiv empfinde, gab es im ersten Dojo mit dem neuen Verfahren keine einzige Codezeile, da eine Stunde lang das Problem eruiert und Begrifflichkeiten diskutiert wurden. Wohlgemerkt handelte es sich dabei um ein echtes Szenario aus einer unserer Problemdomäne, d.h. wir verwendeten keine der üblichen Katas. Umso schneller kamen wir dann im zweiten Training zu einer fertigen Lösung. Mit ein wenig Überziehung erreichten wir nach 1.15h die Ziellinie.

TDD 2.0 empfinde ich als längst überfällige Erweiterung bzw. Kritik. Wir werden in Zukunft auf diese Weise weiterarbeiten. Ein Punkt, der für mich allerdings weiterhin in Frage gestellt werden sollte: Müssen Coding Dojos an Katas durchgeführt werden? Warum nicht an einem echten, auf ein notwendiges Minimum reduzierten Praxisbeispiels aus der Problemdomäne trainieren? Oder alternativ für die Administration ein kleines Hilfsprogramm schreiben, dass die tägliche Arbeit automatisiert? Kürzlich half ich meinem ehemaligen Fussballverein beim Realisieren des DFB Reglements bzgl. Stammspieler. Gelöst habe ich es vorerst über Excel, sodass immer noch Handarbeit seitens des Vorstands notwendig ist. Doch dieses Thema kommt auf unsere Coding Dojo Agenda. Es gibt viele gemeinnützige Organisationen oder Sportvereine, die sich über Hilfe der IT zu kleinen Wehwehchen freuen würden!

Entity Framework Webcasts – Stored Procedures und SQL Queries

Im sechsten Teil meiner Entity Framework Webcast Serie zeige ich, wie die IUnitOfWork erweitert werden muss, um SQL Abfragen und Befehle auszuführen. Im Fokus stehen Value Functions und Stored Procedures.

 

 

Dafür stellt das Entity Framework 2 Schnittstellen bereit:

Ein wichtiger Hinweis an dieser Stelle, welcher eingehender in meinem Webcast erwähnt wird: Zum Ausführen einer SQL Query existieren 2 Implementierungen:

Der wesentliche Unterschied besteht darin, dass im ersten Fall die zurückgegebenen Entitäten nicht getrackt werden, im zweiten hingegen schon. Das ist leicht nachvollziehbar, so muss bei DbContext.Database.SqlQuery ein generischer Parameter, der den Rückgabewert darstellt, übergeben werden. Im Falle von DbSet.SqlQuery ist dies nicht nötig, schließlich befindet man sich zum Zeitpunkt der Abfrage auf einem konkreten Set an Entitäten, die über den Context aufgelöst wurden.

Meine vorgestellte Lösung geht den gleichen Weg wie die in Teil 3 beschriebenen Queries, d.h. es werden quasi SQL Query und Command Repositories angelegt, um einer Streuung innerhalb der Anwendungslandschaft entgegenzuwirken.

Schließlich noch zwei Sicherheitshinweise:

  • Die SQL Befehle werden mit den Berechtigungen des Contexts bzw. des darunterliegenden Sicherheitstoken ausgeführt
  • Beim Erstellen des SQL Strings sollte aus Sicherheitsgründen gegenüber Injections mit String.Format() oder alternativ mit SqlParameters gearbeitet werden.

 

I wrote this blog post as an answer of a question from the Netherlands, so I want to complete this article with a quote:

“When you execute a SqlQuery from Database, the results are never tracked by the context, even if the query returns types that are in the model an known by the context. If you do not want the results to be changed-tracked, use DbContext.Databae.SqlQuery.

Results of a DbSet.SqlQuery will be tracked by the context. Ensuring that results are change-tracked is the primary reason you would choose to use DbSet.SqlQuery over Database.SqlQuery.” (Programming Entity Framework, Page 226)

 

Weitere Quellen:

%d Bloggern gefällt das: