Archiv für den Monat März 2012

Meeting Outside

Diese Woche hielten wir unser wöchentliches IT Meeting bei strahlendem Sonnenschein im Biergarten ab. Einfach toll!

CIMG0059CIMG0055

CIMG0079CIMG0060

CIMG0073CIMG0049

CIMG0058CIMG0061

Werbung

Meine tägliche Portion Git

Here are some Git Aliases of mine. Just insert them in the "[alias]” section into your global .gitconfig, usually placed in your home directory.

   1: review = log -1 --patch

   2: unstage = reset head

   3: aa = add --all

   4: au = add --update

   5: s = status

   6: p = pull

   7: l = log --oneline -10

   8: k = !gitk --all & --all &

   9: aua = !git add --update && git commit --amend --reuse-message=HEAD

  10: aaa = !git add --all && git commit --amend --reuse-message=HEAD

  11: amend = commit --amend --reuse-message=HEAD

  12: aac = !sh -c 'git add --all && git commit -m \"$1\"' -

  13: aucp = !sh -c 'git add --update && git commit -m \"$1\" && git push' -

  14: aacp = !sh -c 'git add --all && git commit -m \"$1\" && git push' -

From now on, you can type in your git bash

git aacp “commit message”

in order to add all, commit and push your respository.

Castle Windsor – Handy Ruse Part III

In this blog entry I published code for an IoC Initializer. The following container Integration Test tries to create an instance of each registered service that is not of type IAmNotTestable. Definitely an Integration Tests that every application needs!

Integration Test of the container using Machine.Specifications as UnitTesting Framework:

   1: using System;

   2: using System.Diagnostics;

   3: using System.Linq;

   4: using Castle.MicroKernel;

   5: using Castle.Windsor;

   6: using comWORK.Contracts;

   7: using comWORK.Infrastructure.IoC;

   8: using Machine.Specifications;

   9: using Machine.Specifications.Utility;

  10:  

  11: namespace UAR.IntegrationTests

  12: {

  13:     public abstract class ContainerSpecs

  14:     {

  15:         protected static IWindsorContainer CreateContainer()

  16:         {

  17:             return new IoCInitializer()

  18:                     .RegisterComponents()

  19:                     .Container;

  20:         }

  21:     }

  22:  

  23:     [Subject("Container Specs")]

  24:     public class When_the_application_starts_up : ContainerSpecs

  25:     {

  26:         static IHandler[] _handlers;

  27:         static IWindsorContainer _container;

  28:  

  29:         Establish context = () => { _container = CreateContainer(); };

  30:  

  31:         Because of = () => { _handlers = _container.Kernel.GetAssignableHandlers(typeof(object)); };

  32:  

  33:         Cleanup after = () => _container.Dispose();

  34:  

  35:         It should_be_able_to_create_an_instance_of_each_registered_service =

  36:             () => _handlers

  37:                       .Where(

  38:                           handler =>

  39:                           handler.ComponentModel.Implementation.GetInterfaces().Contains(typeof(IAmNotTestable)) == false)

  40:                       .Each(handler => handler.ComponentModel.Services

  41:                                            .Each(service =>

  42:                                            {

  43:                                                Debug.WriteLine(String.Format("{0}: {1}/{2}",

  44:                                                                              handler.ComponentModel.Name,

  45:                                                                              service.Name,

  46:                                                                              handler.ComponentModel.Implementation.Name));

  47:  

  48:                                                if (service.ContainsGenericParameters)

  49:                                                {

  50:                                                    service.GetGenericArguments()

  51:                                                        .Each(argument => argument.GetGenericParameterConstraints()

  52:                                                                              .Each(

  53:                                                                                  constraint =>

  54:                                                                                  _container.Resolve(service.MakeGenericType(constraint))));

  55:                                                }

  56:                                                else

  57:                                                {

  58:                                                    _container.Resolve(service);

  59:                                                }

  60:                                            }));

  61:     }

  62: }

Implementation of IAmNotTestable

   1: public interface IAmNotTestable{}

Notice: I will publish a new version soon that addresses some open problems that i don’t want to mention here.

Castle Windsor – Handy Ruse Part II

In every application you have to initialize the container as part of the bootstrapping process. I moved the bootstrapping logic into a seperate assembly. Here’s the IoC part as fluent API. The code registers all implementations of IWindsorInstaller contained in the folder of the executing assembly. I also have a method “RunStartupConfiguration” that executes the start-method of all components which implement the interface. This could be useful for configuration reason for example.

Implementation of IoCInitializer

   1: public class IoCInitializer : IDisposable

   2: {

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

   4:  

   5:     public IoCInitializer()

   6:     {

   7:         Container = new WindsorContainer();

   8:     }

   9:  

  10:     public void Dispose()

  11:     {

  12:         if (Container != null)

  13:         {

  14:             Container.Dispose();

  15:             Container = null;

  16:         }

  17:     }

  18:  

  19:     public IoCInitializer RegisterComponents()

  20:     {

  21:         var appDomainDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

  22:         var foundAssemblies = FromAssembly.InDirectory(new AssemblyFilter(appDomainDirectory));

  23:  

  24:         Container.Install(foundAssemblies);

  25:  

  26:         return this;

  27:     }

  28:  

  29:     public IoCInitializer RunStartupConfiguration()

  30:     {

  31:         Container

  32:             .ResolveAll<IStartupTask>()

  33:             .ToList()

  34:             .ForEach(x => x.Start());

  35:         return this;

  36:     }

  37: }

 

Implementation of IStartupTask:

   1: public interface IStartupTask

   2: {

   3:     void Start();

   4: }

 

You can call this in your bootstrapping logic this way:

   1: Container = new IoC.IoCInitializer()

   2:     .RegisterComponents()

   3:     .RunStartupConfiguration()

   4:     .Container;

 

Be careful, the container and class modifiers are public! Instead you should make it internal and integrate it into the assembly that is responsible for bootstrapping.

Castle Windsor – Handy Ruse Part I

Today I want to share some implementations that I use every once in a while:

Scenario 1: You have an assembly that contains all WinForm controls or perhaps ViewModel classes instead. You don’t want to adapt your installer again and again, if you create new controls respectively new ViewModels.

The following snippet shows an Installer that registers all ViewModels in a WPF assembly of mine. Of course I need to decorate my ViewModels with an special interface, in this case IAmViewModel:

   1: public class Installer : IWindsorInstaller

   2: {

   3:     public void Install(IWindsorContainer container, IConfigurationStore store)

   4:     {

   5:         container.Register(Components().ToArray());

   6:     }

   7:  

   8:     private static IEnumerable<IRegistration> Components()

   9:     {

  10:         yield return Classes.FromThisAssembly()

  11:             .BasedOn<IAmViewModel>()

  12:             .WithServiceSelf()

  13:             .LifestyleTransient();

  14:     }

  15: }

You can afford the same for WinForms. You don’t even have to create an interface:

   1: private static IEnumerable<IRegistration> Components()

   2: {

   3:     yield return Classes.FromThisAssembly()

   4:         .BasedOn<Form>()

   5:         .WithServiceSelf()

   6:         .LifestyleTransient();

   7: }

 

In some little (!) cases it can be useful to inject the container itself into an object. For that reason you can register the container in itself:

   1: Container.Register(

   2:     Component.For<IWindsorContainer>().Instance(Container)

   3: );

UnitTests & Threading – Ist grün wirklich grün?

Ich bin kürzlich auf ein Problem gestoßen: In ReSharper wurden UnitTests grün angezeigt, obwohl diese fehlschlugen. Im konkreten Fall handelt es sich um einen UnitTest im Rahmen von Logik, die parallel abläuft. Tritt in den Threads eine Exception auf, so wird dies nicht als Fehler behandelt. Der UnitTest ist weiterhin grün, wenn der Assert trotzdem korrekt ist.

Beispiel: Stellen wir uns zwei Worker Threads vor, die bei einem Controller nach neuen Druckaufträgen fragen. Der Controller ist als Singleton implementiert (oder idealerweise wird dies schon out of the box vom IoC Container gemacht). Tritt nun eine Exception in den Threads auf, der Assert ist aber trotzdem korrekt, so wird der UnitTest grün angezeigt. Hier der Code dazu:

Implementierung Controller:

   1: class PrintJobMediator : IMediatePrintjobs

   2: {

   3:     //lock object for the method

   4:     private object _lockObject = new object();

   5:  

   6:     //instance of the singleton

   7:     private static volatile PrintJobMediator instance;

   8:  

   9:     //lock object for singleton

  10:     private static object syncRoot = new Object();

  11:  

  12:     //private ctor

  13:     private PrintJobMediator() { }

  14:  

  15:     //returns the singleton instance

  16:     public static PrintJobMediator Instance

  17:     {

  18:         get

  19:         {

  20:             if (instance == null)

  21:             {

  22:                 lock (syncRoot)

  23:                 {

  24:                     if (instance == null)

  25:                         instance = new PrintJobMediator();

  26:                 }

  27:             }

  28:  

  29:             return instance;

  30:         }

  31:     }

  32:  

  33:     int _result;

  34:     public int Next()

  35:     {

  36:         lock (_lockObject)

  37:         {

  38:             System.Threading.Thread.Sleep(1000);

  39:             _result += 1;

  40:  

  41:             if (_result == 1)

  42:                 throw new ApplicationException();

  43:         }

  44:  

  45:         return _result;

  46:     }

  47: }

Unit Test:

   1: [Subject(typeof(PrintJobMediator))]

   2: public class When_2_worker_ask_for_new_jobs

   3: {

   4:     static PrintJobMediator _jobMediator;

   5:     static Thread _thread1;

   6:     static Thread _thread2;

   7:     static TimeSpan _timeTaken;

   8:  

   9:     Establish context = () =>

  10:     {

  11:         _jobMediator = PrintJobMediator.Instance;

  12:         _thread1 = new Thread(() => _jobMediator.Next());

  13:         _thread2 = new Thread(() => _jobMediator.Next());

  14:     };

  15:  

  16:     Because of = () =>

  17:     {

  18:         _timeTaken = Measure.Time(() =>

  19:         {

  20:             _thread1.Start();

  21:             _thread2.Start();

  22:             _thread1.Join();

  23:             _thread2.Join();

  24:         });

  25:     };

  26:  

  27:     It should_run_jobs_sequentially = () => _timeTaken

  28:         .ShouldBeGreaterThanOrEqualTo(TimeSpan.FromSeconds(2));

  29: }

  30:  

  31: public static class Measure

  32: {

  33:     public static TimeSpan Time(Action timedAction)

  34:     {

  35:         var watch = new System.Diagnostics.Stopwatch();

  36:         watch.Start();

  37:  

  38:         timedAction();

  39:  

  40:         watch.Stop();

  41:         return watch.Elapsed;

  42:     }

  43: }

 

In ReSharper wird der Test als erfolgreich angezeigt:

image

Wenn man sich die Details anschaut, sieht man folgendes:

image

In der Implementierung schmeiße ich im ersten Thread eine Exception (Zeile 42). Da trotzdem die Gesamtdauer der Ausführung 2 Sekunden ist, ist der Assert korrekt. Der UnitTest bricht nicht ab, weil seit .NET 2.0 eine neue Policy greift (Name fällt mir gerade nicht mehr ein), die den Abbruch des Main Thread durch Exceptions in separaten Threads verhindert.

Zwischenfazit Social Media – Teil 5

Strategie braucht Richtung

image

Als erstes Projekt befassten wir uns mit den Social Media Guidelines. Ich kann nur empfehlen, diese als ersten Punkt auf die Agenda zu schreiben, bevor man im Social Web aktiv wird. Die Task Force wurde in mehrere kleine Gruppen aufgeteilt, die jeweils von einem IT-ler betreut wurden. Primär schauten wir uns Guidelines von anderen Firmen an, lasen Empfehlungen dazu (z.B. auf www.chip.de und www.cio.de) und kommunizierten mit der Geschäftsleitung bzw. dem Firmenanwalt. Manche Firmen haben wir direkt angeschrieben, um zu erfragen, wie sie mit dem Thema umgehen. Besonders gewinnbringend waren zwei Vorträge auf der Social Media Night Stuttgart.

Einen wesentlichen Punkt haben wir intensiv diskutiert: Wie werden die Guidelines vermittelt und in welcher Form lässt man sie dem einzelnen Mitarbeiter zukommen. Klar ist, dass es keinen Sinn macht die Richtlinien lediglich in Papierform rauszugeben. In dem Fall muss man sich nicht wundern, wenn sich dann ein Mitarbeiter nicht korrekt verhält. Deshalb setzten wir auf zwei Wege:

  • Informieren bzw. schulen und
  • Unterschrift durch den Einzelnen.

Das Thema Schulung wird in einem späteren Eintrag aufgegriffen, deshalb werde ich an dieser Stelle auf eine Ausführung verzichten. Trotzdem möchte ich darauf hinweisen, welchen Vorteil die in den ersten Teilen erwähnte abteilungsübergreifende Integration bietet: In jeder Abteilung war mindestens eine Person der Gruppe, die bei Fragen kompetent Auskunft geben konnte!

Mit der Unterschrift bestätigte der Mitarbeiter, dass er das Dokument zur Kenntnis genommen hat. Natürlich wollten und wollen wir niemanden einen Strick daraus drehen, sodass es sich nicht um einen bürokratischen Vertrag handelt. Das erkennt man bereits an dem Wort Guidelines, also Richtlinien. Vielmehr gewährleisteten wir damit, dass der Inhalt auch wirklich durchgelesen wurde.

Unsere Social Media Guidelines findet ihr hier.

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.

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.

Excel Pivot Auswertung mit dem SQL Server

Unser Controlling will immer wieder von mir aufs Neue Auswertungen. Besonders engagiert wird danach gefragt, wenn der Wirtschaftsprüfer im Haus ist. Um nun nicht ständig aktiv werden zu müssen, habe ich eine View definiert, die alle benötigten Spalten enthält. Das kann z.B. so aussehen:

 

   1: CREATE VIEW [dbo].[MonthlyAnalysis]

   2: AS

   3: SELECT     Artikelklassen.Text AS Klasse, Artikelkreise.Text AS Kreis,

   4:     Artikelstamm.article_number_formatted AS Artikelnummer,...

   5: FROM         Artikelstamm Left Outer JOIN ...

   6: where (Artikelbestände.ID_Lager = 1) and ...

   7: GROUP BY Artikelklassen.Text, Artikelkreise.Text...

Anmerkung: Da ich keine interne Datenstrukturen offenlegen will, habe ich das Statement nicht vollständig gepostet.

 

Nun habe ich eine Exceltabelle erstellt, welche genau diese View abruft. Dazu müsst ihr einfach im Reiter Daten auf “Aus anderen Quellen” klicken und dort “von SQL Server” auswählen. Logischerweise müssen die Personen, die mit der Exceldatei arbeiten, auch über die entsprechenden Berechtigungen zum Anzeigen der Daten verfügen.

image

Füllt dann die Daten in den folgenden Dialogen aus, welche unter anderem so aussehen:

image

Am Schluss wählt ihr dann die von euch erzeugte View aus. Danach klickt ihr auf die Tabelle und erzeugt wie in folgendem Screenshot beschrieben das Sheet mit der Pivottabelle

image

Das ganze könnte beispielsweise so aussehen:

image

image

Anmerkung: Da ich die Kennzahlen nicht vollständig nach außen geben will, habe ich diese verwischt.

Meine tägliche Portion Git

Gehen wir davon aus, dass wir lokal 2 Branches haben mit den Namen Branch1 und Branch2. Dann sind beide Branches unter zwei Namen zu erreichen.

image

Dem eigentlichen Alias, sprich der Branch Name, z.B. Branch1. Außerdem unter dem eindeutigen SHA. Sprich folgende Befehle sind syntaktisch gleich:

  • git checkout Branch1
  • git checkout 56789

Mit git checkout wechselt man zwischen Branches. Steht man aktuell auf Branch1, so ist dieser noch unter einem dritten Alias erreichbar: HEAD.

Wenn ich nun über git checkout Branch2 mache, so wechselt der HEAD Pointer auf Branch2, sodass Branch1 nur noch unter 2 Namen erreichbar ist, wohingegen Branch2 nun 3 Namen hat: Den SHA, Branch2 und HEAD.

Gut zu wissen: Über git reflog kann man sich die komplette Historie von HEAD anzeigen, sprich alle Änderungen die man auf jedem Branch, auf dem man jemals war, anzeigen lassen und ggf. darauf wechseln.

Lokale Branches lässt man sich über git branch anzeigen, Remote Branches über git branch –r (git branch –a listet lokale und remote Branches auf). Wichtig zu wissen: Per Default sind Branches, die man anlegt, lokal. Über git push origin branchname -u (funktioniert immer, egal wo man steht) kann man den Branch veröffentlichen. Wird ein Branch veröffentlicht, so wird er auch in die .git/config (sprich die Repository spezifische config) eingetragen! Bei lokalen ist dies nicht der Fall. Wenn ein Kollege einen Branch veröffentlicht hat, so kann man diesen sich lokal ziehen:

  • git fetch (lädt erst mal eine lokale Kopie des Origin Repository runter)
  • git checkout –b lokalername –track origin/remotename

ziehen.

Mit git checkout –b name erzeugt man übrigens einen lokalen Branch.

ReSharper–Patterns

Wer ReSharper einsetzt, kann seine Code Qualität dadurch erhöhen, dass er die Patterns Funktionalität in der Code Inspection nutzt. Damit erkennt ReSharper typische Anti Patterns. Ein Beispiel für ein Anti Pattern habe ich hier beschrieben.

JetBrains bietet euch bereits eine definierte Liste, welche ihr hier (Download von ‘Sample pattern catalog for Structural Search and Replace’) findet. Dabei handelt es sich um eine XML File, welche ihr in den Optionen unter Code Inspection – Custom Patterns importieren könnt.

image

Anti Patterns–Any vs. Count

 

   1: static void Test()

   2: {

   3:     var list1 = new List<int> { 1, 2, 3, 4, 5 };

   4:  

   5:     if (list1.Count > 0)

   6:     {

   7:         Console.WriteLine("if - count");

   8:     }

   9:     if (list1.Any())

  10:     {

  11:         Console.WriteLine("if - any");

  12:     }

  13:  

  14:     Console.ReadLine();

  15: }

 

Wo liegt der Unterschied zwischen list1.Count und list1.Any? In erstem Fall wird die Liste durchiteriert, um herauszufinden, wie viele Elemente in der Liste sind. Bei Any wird nur geprüft, ob überhaupt ein Element in der Liste ist. Bei einer Prüfung > 0 ist also Any die bessere Wahl, weil die Liste nicht durchiteriert werden muss! Bei 100000 Elementen kann sich das durchaus lohnen…

image

ReSharper & IoC Container

Wer in seiner Architektur auf IoC Container einsetzt, der bekommt bei ReSharper immer die Meldung “Possible NullReferenceException”, wenn er z.B. im Konstruktor den NULL-check unterlässt. Allerdings ist diese Prüfung meiner Meinung nach unnötig, da der Container ja entweder eine Instanz erzeugen kann oder ggf. eine Exception schmeißt. Deshalb würde ich diese Prüfung in ReSharper abschalten:

Geht dazu in eure ReSharper Optionen (Achtung: Ab Version 6.1 gibt es ja unterschiedliche Layer an Optionen. Achtet darauf, dass ihr im richtigen Layer seid!). Danach findet ihr unter Code Inspection – Inspection Severity im Tab All, wenn ihr beim Filter “null” eingebt unter der Kategorie “Potential Code Quality Issues” die Option “Possible System.NullReferenceException”, welche ihr auf “Do not show” stellen müsst.

image

Social Media Monitoring Consultant gesucht

Wir suchen für unseren Betrieb eine Firma, die uns beim Social Media Monitoring unterstützt. Mehr Infos findet ihr auf unserem IT Team Blog.

%d Bloggern gefällt das: