Archiv für den Monat August 2011

Inversion of Control and Entity Framework

Today i want to show you my approach to resolve the requested entity framework object context at runtime. Starting point:

  • First, i want to have just one implementation of an IUnitOfWork to resolve any kind of repository like Repository<Order>
  • Second, my unit of work should autodiscover the proper context for my requested type of domain model as i have different databases and object contexts. For example, Order is a domain object of my domain model (namespace Domain.ComWork) according to the context ‘comwork’, which is mapping to the database ‘comwork’. There’s another domain object like Customer in my domain model (namespace Domain.MyHeco) according to the context ‘myheco’, which is mapping to the database ‘myheco’.

So how can i achieve this? I will use an IoC container like Castle.Windsor. You can add it to your Visual Studio project by the nuget command “install-package Castle.Windsor”. I want to mention that this scenario needs a little bit of advanced IoC techniques because the dependent component has to be resolved at runtime. So you’re not able to register a dedicated component for an interface. Instead you’ve got to use a facility. Allright, so we tell the container that we will register a facility:

   1: container.AddFacility<TypedFactoryFacility>();

 

In line 1 we tell the container that it has to load the necessary infrastructure for facilities. Let’s take a look at the registration process. Here’s my method that will return me an IEnumerable of IRegistration.

   1: static IEnumerable<IRegistration> Components()

   2: {

   3:     yield return Component

   4:         .For<IContextFactory>()

   5:         .AsFactory(c => c.SelectedWith<ContextFactoryHandlerSelector>());

   6:     yield return Component

   7:         .For<ContextFactoryHandlerSelector>();

   8:     yield return Component

   9:         .For<IUnitOfWork>()

  10:         .ImplementedBy<UnitOfWork>();

  11:     yield return Component

  12:       .For<ComWorkContext>()

  13:       .Named("comworkcontext");

  14:     yield return Component

  15:       .For<MyHecoContext>()

  16:       .Named("myhecocontext");

  17: }

 

Here’s the good news: Castle Windsor has an out of the box feature that creates you the needed factory. In other words: The container creates automatically the factory. You’re code is unaware of the container. Take a look at this article. If you want to use this you’ve have to follow some conventions. In my approach i decided to develop my own implementation to follow my own convetions. Take a look at line 5.  With “.AsFactory” i tell the container that i don’t register a concrete implementation for that service (IContextFactory). If i would follow the conventions of Castle.Windsor calling AsFactory() would be enough.

Here’s the code for my own implementation of a TypedFactoryComponentSelector (this would be auto generated by using just AsFactory without parameters):

   1: public class ContextFactoryHandlerSelector : ITypedFactoryComponentSelector

   2: {

   3:     public TypedFactoryComponent SelectComponent(MethodInfo method, 

   4:         Type type, object[] arguments)

   5:     {

   6:         var requestFor = method.GetGenericArguments().First();

   7:         

   8:         var @namespace = string.Format("{0}context", 

   9:             requestFor.Namespace.ToLower()

  10:             .Replace("domain.",""));

  11:         

  12:         return new TypedFactoryComponent(@namespace, method.ReturnType, null);

  13:     }

  14: }

 

My convention is pretty simple: The name of my object context is the same as the namespace of my model without the string “domain.” and with “context” appended.

Sample: Full name of my domain object: “domain.comwork.order”

  • use just the namespace –> domain.comwork
  • replace domain –> comwork
  • add context –> comworkcontext

I have two kind of domain models (domain.comwork and domain.myheco) so i need two contexts (comworkcontext and myhecocontext). Every context is registered:

   1: yield return Component

   2:   .For<ComWorkContext>()

   3:   .Named("comworkcontext");

   4: yield return Component

   5:   .For<MyHecoContext>()

   6:   .Named("myhecocontext");

 

Now we’ve got it: We have a facility that invokes a call to my self implemented factory if a service (defined in the interface IContextFactory) is requested. The factory returns the name of the needed context at runtime. My Interface looks like this:

   1: public interface IContextFactory

   2: {

   3:     ObjectContext GetContextFor<T>();

   4: }

And here’s the generic part. If i call GetContextFor<domain.comwork.order> i will get my comworkcontext. If i call GetContextFor<domain.myheco.customer> i will get my myhecocontext.

The last step is to inject the factory in my UnitOfWork. Nothing easier than that:

   1: public class UnitOfWork : IUnitOfWork

   2: {

   3:     private readonly IContextFactory _factory;

   4:  

   5:     public UnitOfWork(IContextFactory factory)

   6:     {

   7:         _factory = factory;

   8:     }

   9:  

  10:     //here you would return an IRepository<T>

  11:     //this is just a sample code

  12:     public void GetRepository<T>() where T : class 

  13:     {

  14:         Console.WriteLine(_factory.GetContextFor<T>().GetContextName());

  15:     }

  16: }

 

And how can i resolve my concrete UnitOfWork in my program?

   1: static class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:             using (var container = new WindsorContainer())

   6:             {

   7:                 container.AddFacility<TypedFactoryFacility>();

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

   9:  

10: container.Resolve<IUnitOfWork>()

.GetRepository<Domain.ComWork.Foo>();

11: container.Resolve<IUnitOfWork>()

.GetRepository<Domain.MyHeco.Bar>();

  12:             }

  13:     }

  14:  

  15:     static IEnumerable<IRegistration> Components()

  16:     {

  17:         //Registrations...

  18:     }

  19: }

Werbung

Gehaltsverhandlungen – Teil 2

Bereits im Juni hatte ich hier zu diesem Thema gebloggt. Nachdem ich nun das Buch 30 Minuten für Ihre Gehaltserhöhung von Martin Wehrle gelesen habe, wollte ich noch einige wichtige Punkte ergänzen:

Idealerweise führt der Mitarbeiter kontinuierlich ein Leistungstagebuch, welches die Grundlage zur Erstellung einer Leistungsmappe ist. Ich persönlich tendiere aber dazu, dass die “Mappe” lediglich 1-2 Seiten umfassen sollte. Außerdem rate ich selbst dann zu besagtem Leistungsprotokoll, wenn man einen Vorgesetzten hat, der ausgiebig und oft lobt, da das Gedächtnis so seine Tücken aufweist. Zu diesen Führungskräften kann ich mich übrigens nicht zählen, weil ich vom Loben nur im beschränkten Maße etwas halte (dazu ein anderes Mal mehr).

Neben dem eigentlichen Festgehalt, welches schnell seine raue Alltagsfratze in Form von Steuern und Sozialabgaben zeigt, gibt es viele interessante Alternativen, die sowohl für den Arbeitnehmer als auch Arbeitgeber Vorteile aufweisen. Hierzu eine kurze Auflistung, was denn so alles in Frage kommen könnte:

  • Prämie: Einmalzahlung für eine definierte Individualleistung
  • Bonus: Entspricht bei einer GmbH i.d.R. der Gewinnbeteiligung
  • Gratifikation: Einmalzahlung aus besonderem Anlass, z.B. Weihnachtsgeld (wird auch nachträglich ausgezahlt)
  • Provision
  • Belegschaftsaktien
  • Firmenwagen: Hierbei werden z.B. keine Sozialabgaben fällig!
  • Fahrtkosten: Sind niedrig besteuert
  • Direktversicherung: Immer wieder sinnvoll aus meiner Sicht
  • Weiterbildung: Steigert den eigenen Marktwert + die Leistungsfähigkeit im Job
  • Alltagszuschüsse: Zum Beispiel für Handy, Internet, Fitness Club
  • Belegschaftsrabatt

 

Thema Gehaltssprünge:

Speziell dabei habe ich festgestellt, dass viele sehr unsicher sind, was das angeht. Normalerweise liegen diese zw. 3 und 10 Prozent, wobei 10 Prozent recht ambitioniert ist. Bei weniger als 3 Prozent frisst einem die Inflation das bisschen Netto wieder auf. Zwischen 10 und 20 Prozent liegt die Grenze, die vorwiegend dann angekratzt wird, wenn man z.B. eine Projekt-, Team- oder Abteilungsleitung übernimmt.

 

Thema Verhandlungsstrategie:

Nach einer Gehaltserhöhungen sollte man in der Regel zw. 12 und 18 Monaten die Füße stillhalten. Deswegen ist es wichtig, dass man als Angestellter auch mit der Erhöhung für diesen Zeitraum leben kann. In anfangs erwähntem Buch werden ein Minimal- (=Schmerzgrenze), ein Maximal- und ein Alternativziel (z.B. eine der oben aufgelisteten Möglichkeiten) vorgeschlagen. Das halte ich für sinnvoll und gebe diese Empfehlung deshalb so weiter.

 

Bei Argumenten für die eigene Position sollten immer eine der folgenden Kriterien bedient werden:

  • Die Firma spart Geld durch mich
  • Ich bringe der Firma zusätzliches Geld
  • Die Firma profitiert von meiner verbesserten Qualifikation
  • Ich habe meine Leistung und meine Verantwortung ausgebaut

 

Weitere Aussagen, die ich hier sinngemäß oder gar wörtliche wiedergeben will:

  • Jeder Chef weiß: Spitzenmitarbeiter müssen auch Spitzengehälter bekommen
  • Gerade Besserverdiener sind in der Krise wichtiger denn je
  • Selbst-PR: Erfolg hängt zu 10 Prozent von der Leistung ab – und zu 90 Prozent davon, wie man diese Leistung verkauft
  • Ein Lob durch Dritte ist besonders wirksam
  • Dass die Vergütung mit den Dienstjahren wächst, dieses Prinzip gilt nur bei Beamten. Der Staat ist nicht umsonst pleite
  • Klammern Sie Ihren persönlichen Vorteil aus. Zeigen Sie, was die Firma davon hat

 

Als Vorgesetzter finde ich einen Punkt noch ganz besonders heikel: Das Thema Überstunden. Darauf bin ich bereits in meinem letzten Blogeintrag eingegangen, allerdings will ich es nochmal aufgreifen: Man macht sich keinen Gefallen damit, wenn man dies als Mitarbeiter ins Gespräch einbringt. Wenn ich als Vorgesetzter z.B. eine minutiöse Auflistung von Überstunden bekommen würde, dann müsste ich mich fragen, ob mein Mitarbeiter die Arbeit derartig hasst, dass er sich tatsächlich jede Stunde aufschreiben muss. Außerdem gilt wie bei Stempeluhren, die von vielen Vorgesetzten für gut befunden werden, das Argument: Das sagt mir, dass der Mitarbeiter da war, aber nicht ob und was er geleistet hat. Vielleicht (!) ist die Mehrarbeit auch ein Indikator dafür, dass der Angestellte eine zu niedrige Arbeitsleistung hat. Darüber hinaus haben Vorgesetzte oftmals ein deutlich höheres Kontingent an Überstunden, was ggf. zum Streit über Überstunden ausarten könnte. Des Weiteren ist es meinem persönlichen Verständnis nach so, dass in der IT Branche fünf “Überstunden” die Norm und nicht die Ausnahme sind. Wenn man damit nicht leben kann, sollte man sich über einen anderen Beruf Gedanken machen. Zu guter Letzt ist es dann auch noch so, dass der Vorgesetzte diese Überstunden nicht prüfen kann (noch will, noch sollte). Schließlich ist man erfahrungsgemäß während der Arbeitszeit auch mal privat im Netz unterwegs oder telefoniert, sodass mir die komplette Thematik zu wischi waschi ist. Und vergesst eines nicht: Überstunden zeigen ihre Auswirkung hoffentlich in Form von besseren Ergebnissen. Diese wiederum kann man sehr gut als Argument einbringen!

RTL Explosiv versteht Social Media nicht

„Wenn Unrecht zu Recht wird, wird Widerstand zur Pflicht!“ – Bertolt Brecht

Das haben sich heute wohl viele aus der Social Media Community gedacht, denn aus einem Beitrag von RTL Explosiv über Besucher der gamescom Köln entwickelte sich ein regelrechtes Facebook Lauffeuer. Auf die Diskussion über das Thema des Beitrags und wie dieses vermittelt wird, will ich allerdings nicht eingehen, stattdessen geht es mir (v.a. als Social Media Manager bei uns im Unternehmen) um die Art und Weise wie RTL Explosiv bzw. die Verantwortlichen der Fan Page mit der Kritik in Form von Kommentaren umgegangen sind.

Ganz simpel ausgedrückt: Die Reaktion deckte so ziemlich alles ab, was man niemals tun sollte! Nicht erwünschte respektive negative Kommentare wurden einfach gelöscht. Eine meiner Arbeitskolleginnen wurde – zumindest hat es so den Anschein – von weiteren Beiträgen ausgeschlossen (Anm.: Ihr Kommentar rechtfertigt das in keiner Weise!). Eine offizielle Stellungnahme vermissen ich und vermutlich viele weitere bis jetzt noch. Lediglich der Reporter Tim Kickbusch, der an dem Beitrag beteiligt war, entschuldigte sich in seinem persönlichen Profil und beteuerte, dass er niemanden lächerlich machen wollte.

 

image_thumb[4]

 

Während des Verfassens dieses Blogeintrags hat er allerdings inzwischen auch seine Pinnwand vor öffentlichem Zugriff gesperrt. Meine Kollegin kommentierte das wie folgt: “Tja, findet er es wohl doch nicht mehr so witzig”.

Ein weiterer Blick just in diesem Moment brachte weitere Informationen zu Tage:

 

image_thumb[8]

 

Überrascht bin ich von der schnellen, koordinierten und geschlossenen Reaktion nicht – Ganz im Gegenteil! Ich lege den Verantwortlichen dringend nahe, dass sie sich näher mit Social Media Guidelines bzw. allgemein mit der Community im Netz befassen. Viele Regeln, wie sie vielleicht abseits des Internets existieren, gelten hier nicht mehr – und das zu Recht! Ehrlichkeit, Transparenz, Offenheit und nicht zuletzt das Zuhören und Zugeben von Fehlern haben für uns – die Community – höchsten Stellenwert. Charaktereigenschaften, die im realen Leben vielleicht schon auf der Strecke geblieben sind…

 

Verabschieden will ich mit den Worten: "Offenheit verdient immer Anerkennung." – Otto von Bismarck

Data Annotations für valide DTOs

Wer viel mit DTOs arbeitet, der sollte sich in jedem Fall Data Annotations aus dem .NET Framework anschauen. Ich habe diese kürzlich wieder für ein DTO zur Speicherung der Database Configuration verwendet. Das DTO sieht wie folgt aus:

   1: public abstract class DatabaseConfig

   2: {

3: [System.ComponentModel.DataAnnotations.Required(ErrorMessage = "Bitte den

Instanznamen der Datenbank angeben.")]

   4:     public string InstanceName { get; set; }

   5:  

6: [System.ComponentModel.DataAnnotations.Required(ErrorMessage = "Bitte den

Datenbanknamen angeben.")]

   7:     public string DatabaseName { get; set; }

   8:  

   9:     public string UserName { get; set; }

  10:  

  11:     public string Password { get; set; }

  12:  

13: [System.ComponentModel.DataAnnotations.Required(ErrorMessage = "Bitte die

Einstellung für IntegratedSecurity setzen.")]

  14:     public bool IntegratedSecurity { get; set; }

  15: }

 

Dabei handelt es sich nur um ein sehr einfach Beispiel. Es ist problemlos auch möglich Ranges für Zahlen anzugeben, String-Längen zu definieren oder gar ganz eigene Annotations zu bauen, um z.B. Emailadressen zu validieren.

Was jetzt noch fehlt ist eine Implementierung eines Validator. Ich habe das Interface wie folgt definiert:

   1: public interface IValidator<in TIn>

   2: {

   3:     /// <summary>

   4:     /// Liefert die Fehlermeldungen zu allen ungültigen Werden als String zurück

   5:     /// </summary>

   6:     /// <param name="input"></param>

   7:     /// <returns></returns>

   8:     string ToString(TIn input);

   9:  

  10:     /// <summary>

  11:     /// Liefert eine Auflistung aller ungültigen Werte

  12:     /// </summary>

  13:     /// <param name="input"></param>

  14:     /// <returns></returns>

  15:     ICollection<string> GetMessages(TIn input);

  16:  

  17:     /// <summary>

  18:     /// Prüft, ob das zu validierende Objekt gültig ist

  19:     /// </summary>

  20:     /// <param name="input">Das zu validierende Objekt</param>

  21:     /// <returns>true, wenn valide</returns>

  22:     bool IsValid(TIn input);

  23: }

 

Die Implementierung speziell für die Validierung von Data Annotations (das Interface lässt sich schließlich auch noch für andere Validierungen verwenden) sieht so aus:

   1: public class DataAnnotationsValidator<TIn> : IValidator<TIn>

   2: {

   3:     public string ToString(TIn input)

   4:     {

   5:         var invalidProperties = new StringBuilder();

   6:         foreach (var errorMessage in GetErrors(input))

   7:         {

   8:             invalidProperties.AppendLine(errorMessage);

   9:         }

  10:  

  11:         return invalidProperties.ToString();

  12:     }

  13:  

  14:     public ICollection<string> GetMessages(TIn input)

  15:     {

  16:         return GetErrors(input).ToList();

  17:     }

  18:  

  19:     public bool IsValid(TIn instance)

  20:     {

  21:         var invalidProperties = from prop in typeof (TIn).GetProperties()

22: from attribute in prop.GetCustomAttributes(false).

OfType<ValidationAttribute>()

  23:                                 where !attribute.IsValid(prop.GetValue(instance, null))

  24:                                 select attribute;

  25:  

  26:         return invalidProperties.Count() == 0;

  27:     }

  28:  

  29:     private static IEnumerable<string> GetErrors(TIn instance)

  30:     {

  31:         return from prop in typeof(TIn).GetProperties()

  32:                from attribute in prop.GetCustomAttributes(false).OfType<ValidationAttribute>()

  33:                where !attribute.IsValid(prop.GetValue(instance, null))

  34:                select attribute.FormatErrorMessage(prop.Name);

  35:     }

  36: }

 

Und schon in der Bibel steht geschrieben: Entwickle testgetrieben. Deswegen noch zum Abschluss meine Specs (alles in eine Klasse mit dem Namen DataAnnotationsValidatorSpecs.cs einfügen), geschrieben mit dem Framework Machine.Specifications (gibt es auch als NuGet-Package: install-package Machine.Specifications):

   1: public class DataAnnotationsValidatorTestBase

   2: {

   3:     protected static DtoTestClass Config = new DtoTestClass();

   4:  

   5:     public class DtoTestClass

   6:     {

7: [System.ComponentModel.DataAnnotations.Required(ErrorMessage = "Bitte den

Datenbanknamen angeben.")]

   8:         public string Database { get; set; }

   9:         public string Server { get; set; }

  10:         public string User { get; set; }

  11:     }

  12: }

  13:  

  14: public class When_an_invalid_object_is_passed : DataAnnotationsValidatorTestBase

  15: {

  16:     Establish context = () =>

  17:     {

  18:         _validator = new DataAnnotationsValidator<DtoTestClass>();

  19:         Config.Database = string.Empty;

  20:  

  21:     };

  22:  

  23:     private Because of = () => _isValid = _validator.IsValid(Config);

  24:  

  25:     private It should_evaluate_it_as_invalid = () => _isValid.ShouldBeFalse();

  26:  

  27:     private static DataAnnotationsValidator<DtoTestClass> _validator;

  28:     private static bool _isValid = true;

  29: }

  30:  

  31: public class When_an_valid_object_is_passed : DataAnnotationsValidatorTestBase

  32: {

  33:     Establish context = () =>

  34:     {

  35:         _validator = new DataAnnotationsValidator<DtoTestClass>();

  36:         Config.Database = "bac";

  37:  

  38:     };

  39:  

  40:     private Because of = () => _isValid = _validator.IsValid(Config);

  41:  

  42:     private It should_evaluate_it_as_valid = () => _isValid.ShouldBeTrue();

  43:  

  44:     private static DataAnnotationsValidator<DtoTestClass> _validator;

  45:     private static bool _isValid = false;

  46: }

  47:  

  48: public class When_an_object_has_no_annotations

  49: {

  50:     internal class test

  51:     {

  52:  

  53:     }

  54:  

  55:     Establish context = () =>

  56:     {

  57:         _validator = new DataAnnotationsValidator<test>();

  58:  

  59:     };

  60:  

  61:     private Because of = () => _isValid = _validator.IsValid(new test());

  62:  

  63:     private It should_evaluate_it_as_valid = () => _isValid.ShouldBeTrue();

  64:  

  65:     private static DataAnnotationsValidator<test> _validator;

  66:     private static bool _isValid = false;

  67: }

  68:  

69: public class When_an_object_with_one_invalid_property_is_passed :

DataAnnotationsValidatorTestBase

  70: {

  71:     Establish context = () =>

  72:     {

  73:         _validator = new DataAnnotationsValidator<DtoTestClass>();

  74:         Config.Database = string.Empty;

  75:  

  76:     };

  77:  

  78:     private Because of = () => _messages = _validator.GetMessages(Config);

  79:  

  80:     private It should_evaluate_exactly_this_property_as_invalid = () =>

  81:     {

  82:         (_messages.Count == 1).ShouldBeTrue();

  83:         _messages.Aggregate(string.Empty, (current, message) => current + message)

  84:             .Contains("Datenbanknamen").ShouldBeTrue();

  85:     };

  86:  

  87:     private static DataAnnotationsValidator<DtoTestClass> _validator;

  88:     private static ICollection<string> _messages;

  89: }

T-SQL Abfrage für Tags

Gerade musste ich eine etwas schwierigere Auswertung machen. Die Aufgabenstellung dazu war:

“Ermittle alle Kunden, die weder der Branche Handel noch Verbraucher zugeordnet sind.”

Nun muss man wissen, dass wir die Branchen an einem Kunden quasi wie Tags haften. Im ERP sieht das so aus:

image

Dementsprechend gibt es zw. der Tabelle Kunde und Branche eine n:m Beziehung. Ein Kunde kann keinen Tag, nur einen oder mehrere haben. Ein Tag kann wiederum keinem Kunden, genau einem oder mehreren zugeordnet sein. Gemäß der Normalisierungsregeln für relationale Datenbanken ist die Tabelle Branchen so aufgebaut, dass z.B. für das oben genannte Beispiel 4 Einträge zu dem Kunden mit der ID 7001 drin stehen. Pro Tag jeweils einen Eintrag.

Das schwierige war nun, dass ich den kompletten Kundenstamm durchlaufen und für jeden gefundenen Kunden eine Unterabfrage feuern musste, die prüft, ob in irgendeinem der zugeordneten Tags der Begriff Handel oder Verbraucher vorkommt. Im Programmcode wäre das eine klassische For Each Schleife, welche im inneren nochmal eine For Each Schleife enthält (Anmerkung: Wenn man sich mit LINQ auskennt, geht es auch einfacherSmiley).

Wie macht man das nun mit T-SQL am einfachsten, wenn man zu faul ist zum Programmieren? Nachdem ich mich mit dem Wissensvermittler meines Vertrauens (Google) beraten habe, war die eleganteste und einfachste Lösung das Verwenden des Befehls

For XML Path(“)

Ein konkretes Beispiel findet ihr hier :

SELECT p1.CategoryId,
     
( SELECT ProductName + ‚,‘
          FROM Northwind.dbo.Products p2
         WHERE p2.CategoryId = p1.CategoryId
         ORDER BY ProductName
           FOR XML PATH(“) ) AS Products

  FROM Northwind.dbo.Products p1
GROUP BY CategoryId ;

In der erzeugten Spalte steht dann der XML String. Bei uns sah das so aus:

<Beschreibung>Maschinenbau </Beschreibung><Beschreibung>Anlagenbau/ Apparatebau</Beschreibung>

Nun konnte ich mit LIKE prüfen, ob in diesem z.B. Handel oder Verbraucher steht.

Ausschreibung für Diplomstellen

Ich suche für unsere IT Abteilung noch Diplomanden zu den unterschiedlichsten IT Themen. Neben diversen Vorschlägen meinerseits, die ihr unter http://goo.gl/Ij58U findet, könnt ihr auch gerne selbst welche für die Bereiche

  • Softwareentwicklung mit .NET
  • Webentwicklung für unser CMS Typo3 mit PHP5
  • System- und Netzwerkadministration
  • Marketing / Public Relations

einreichen. Speziell im Umfeld des Web und Marketings sind SEO und Social Media Themen für uns von besonderem Interesse.

Wir bieten flexible Arbeitszeiten, eine adäquate Vergütung, sehr gut ausgerüstete Arbeitsplätze, neuste Technologien und Software, ein super Arbeitsklima und ein junges, hochmotiviertes IT Team. Eine anschließende Festanstellung ist denkbar. Ihr könnt alle IT-ler per Email, Telefon, Xing oder auch Facebook erreichen. Die Profile dazu findet ihr über unsere Fanpage https://www.facebook.com/hecogmbh, indem ihr nach den Namen von uns sucht. Martin Edelmann dürfte in diesem Fall der beste Ansprechpartner sein, da er vor 2 Jahren ebenfalls seine Diplomarbeit bei uns gemacht hat.

Wer aus Karlsruhe kommt, kann sich der IT Fahrgemeinschaft anschließen. In Remchingen-Nöttingen ist man von Karlsruhe mit dem Auto in ca. 20 Minuten. Mit der Bahn kommt man vom Durlacher Tor in unseren Nachbarort Wilferdingen ebenfalls in 20 Minuten (Verzögerungen durch die Baustellensituation nicht eingerechnet).

Facebook Fanpage – Einträge mit dem eigenen Namen

Wer eine Fanpage in Facebook für seine Firma als Administrator verwaltet, der schreibt per Standardeinstellung im Namen der Firma, auch wenn er mit seinem eigenen Profil angemeldet ist. Ich bin bei der Firma heco beispielsweise als Administrator der Fanpage angelegt. Wenn ich auf die Pinnwand schreibe oder Fotos kommentiere, dann zeigt es statt meinem Namen immer den Namen der Firma an.

Das ist nicht immer gewünscht. Abstellen kann man dies, indem man auf die Fanpage wechselt und dann rechts oben auf “Seite bearbeiten” klickt. Auf der Folgeseite klickt ihr dann links auf “Deine Einstellungen”. Nun könnt ihr in der Mitte den Haken setzen: “Kommentiere und poste Beiträge auf deiner Seite immer unter dem Namen (Fanpage Name), auch wenn du Facebook als (euer Profilname) verwendest.”

 

clip_image002

LINQ und Fakes

Kürzlich stand ich vor dem Problem, dass ich einen Unit Test schreiben musste, bei dem geprüft wird, ob eine spezielle Methode aufgerufen wurde.

Beispiel: Ich habe einen Controller, der Daten von der DB in die UI lädt. Der Controller ist meine zu testende Unit. Nun will ich prüfen, ob der Controller, wenn er den Load-Befehl erhält, diesen auch korrekt an mein Repository weiterleitet. Die DB Logik habe ich dazu mit FakeItEasy gefakt. Über MustHaveHappened() kann man prüfen, ob auf dem Fake die Save-Methode aufgerufen wurde (vgl. diesen Artikel zu dem Thema).

Nun gibt es ein Problem:

1: var controlsToTranslate = from ctrl in _form.TranslatableControls select

ctrl.TranslationKey;

2: var translations = _translationRepository.LoadTranslations(_languageId,

controlsToTranslate);

Ich ermittle den zu übergebenden Parameter in meiner zu testenden Klasse per LINQ, sodass der Aufruf von Load auf meinem Repository als Parameter eine LINQ Expression ist. Damit ist der Parameter ein Objekt, welches ich in meinem Unit Test nicht nachstellen kann, sprich die Prüfung von FakeItEasy mit (vgl. Zeile 2)

   1: Fake.A

   2:     .CallTo(() => translationRepository.LoadTranslations(0, translationKeys))

   3:     .MustHaveHappened();

 

wird nie erfolgreich sein, da FakeItEasy einen Equals-Vergleich ausführt. Der zweite Parameter in meinem    Test wird immer ein anderes Objekt sein, als das, was in der zu testenden Unit (dem Controller) erzeugt wird.

Die Lösung sieht wie folgt aus:

   1: Fake.A

   2:     .CallTo(() => translationRepository.LoadTranslations(0, 

   3:      A<IEnumerable<string>>.That.Matches(x => x.SequenceEqual(translationKeys))))

   4:     .MustHaveHappened();

 

In Zeile 3 steht die Lösung für meinen Parameter. Hier sage ich, dass der Parameter vom Typ IEnumerable<string> sein muss und dass lediglich die Reihenfolge der Strings, wie sie in IEnumerable stehen, gleich sein muss. Damit habe ich den Equals-Vergleich für Parameter 2 anders implementiert.

Meine Top 7 CIO Topics der nächsten Monate

Ständig liest man von den Zukunftsprognosen diverser Institute wie der Bitkom oder von den kommenden Projekten diverser CIOs großer bis sehr großer Firmen. Hingegen sind Artikel zu den Themen, die die CIOs in KMUs beschäftigen, eher rar. Deshalb habe ich mich entschlossen unsere Projekte und Schwerpunkte der nächsten 12 Monate wiederzugeben:

Social Media:

Trotz unserer Größe (ca. 80 Mitarbeiter) und unserer weniger IT-affinen Branche (Edelstahl) stehen die nächsten 12 Monate ganz im Zeichen des aktuellen Hype Themas Social Media. Intern wollen wir primär das Thema Wissensmanagement in unserem auf SharePoint basierendem Intranet mit Blogs und Wikis aufgreifen. Extern wollen wir v.a. Twitter, Xing und Facebook einsetzen, um unsere Unternehmensstrategien zur Kommunikation, Mitarbeiterakquise, Kundenbindung und zum Marketing bzw. zur Imagebildung zu verstärken respektive zu erweitern. Ein Ansatz hierfür ist z.B. eine Umfrage unter unserer Facebook Fangemeinde, die über neue Funktionen für unsere Homepage (vgl. nächstes Projekt) abstimmen kann. Rückenwind erhält die IT durch eine sehr große Gruppe von ca. 15 Digital Natives, sowie der Geschäftsführung selbst. Nicht zu kurz kommt dabei das “Abholen” und Schulen der Mitarbeiter (vgl. übernächstes Projekt).

Webseite:

Ohne einen Webauftritt geht heutzutage gar nichts mehr. Obwohl wir hier gut aufgestellt sind, werden die nächsten 12 Monate richtig spannend: Unter anderem stehen ein neues Kundenportal (myheco), eine noch stärkere Zusammenführung von Website und unserem hauseigenen ERP (z.B. die direkte Anfrageübernahme), sowie ein Online Shop auf der Agenda. Darüber hinaus werden unsere sehr gefragten Datenblätter (über 3000 Downloads im Monat) um geniale Neuerungen ergänzt. Aber die vermutlich wichtigste Neuerung dürfte der verstärkte Ausbau der Mehrsprachigkeit sein, welcher mit der internen Internationalisierung unserer ERP-Lösung einhergeht. Kleine Anmerkung am Rande: Ich will demnächst hierzu eine auf .NET basierende Bibliothek als Open Source Projekt frei zur Verfügung stellen! Wenn sich überraschenderweise herausstellen sollte, dass wir frühzeitig mit den Projekten fertig werden, dann ist bereits eine mobile App angedacht. Ein interessantes Thema, allerdings für uns noch nicht in dem Maße relevant, wie es in anderen Branchen der Fall ist.

Abholen der Mitarbeiter:

Die IT ist ein Dienstleister. Das sollte inzwischen bei allen IT Leitern angekommen sein. Wir werden diesem Paradigma gerecht, indem wir regelmäßig unsere Mitarbeiter schulen und informieren. So wird es in den nächsten 12 Monaten verstärkt Schulungen in den Bereichen Social Media (wie sichere ich mein Facebook Profil ab, wie verhalte ich mich im Web 2.0) und Sicherheit (Dos und Don’ts) geben. Aber auch die IT selbst wird wöchentlich in fachabteilungsübergreifenden Geschäftsprozessen durch den Geschäftsführer persönlich geschult, um der Rolle als sogenannter Business Enabler noch besser gerecht zu werden. Des Weiteren machen wir halbjährlich Umfragen bzgl. der Zufriedenheit mit der IT. Last but not least geben wir streng nach dem Motto “mehr Transparenz für ein besseres Verständnis” im sechs Monatsrhytmus einen Ist-Soll-Abgleich für die immer ein Jahr im Voraus geplanten Großprojekte der Administration, von denen die Anwender direkt und im stärkeren Umfang betroffen sind, heraus. Ich will an dieser Stelle anmerken, dass ich hiermit keinesfalls Projektmanagement mit weitreichender und starrer Planung (Stichwort Wasserfallmodell in der Softwareentwicklung) gutheiße.

Virtualisierung:

Während wir immer wieder Cloud Computing für uns evaluieren, ist Virtualisierung bei uns inzwischen nicht mehr wegzudenken. Die nächsten 12 Monate werden wir nutzen, um auch die letzten Server, bei denen dies möglich ist, noch zu virtualisieren, um den Return on Investment zu steigern und die Systemlandschaft zu konsolidieren.

Sicherheit:

Das wichtigste Projekt in der Administration wird das Thema Sicherheit in all seinen Facetten sein. Neben der zuvor erwähnten Schulung der Mitarbeiter, gibt es eine Vielzahl an Punkten, die hier abzuarbeiten sind: Backupkonzepte, Notfallstrategien, Firewalls, usw.. Dabei wollen wir es vor allem den Anwendern leicht machen, um die Reaktionszeit der IT zu verkürzen. So führen wir eine spezielle Seite im Intranet ein, die kurz und prägnant eine Anleitung samt Kontaktdaten enthält. Zusätzlich wird mit jeder Abteilung ausgiebig besprochen, welche Daten und Programme essentiell und welche Ausfallzeiten annehmbar sind. Am Ende steht ein sogenannter Disaster Recovery Plan, der jährlich neu evaluiert wird. Entsprechende Ausfall- und Wiederherstellungstests werden je nach Notwendigkeit im 3-, 6- oder 12-Monatstakt durchgeführt. Von den IT-lern wird jeder Einzelne (also nicht nur die Admins) in diesen Prozessen geschult. Auch in der Web- und Softwareentwicklung werden wir nochmal diverse Funktionalitäten auf den Prüfstand stellen! In diesem Kontext überlegen wir, ob wir einen externen Dienstleister ins Boot holen, um unsere Webseite auf Schwachstellen abzuklopfen. Zu guter Letzt geht das Ganze auch mit einer kritischen Betrachtung durch unseren Datenschutzbeauftragten einher.

Outsourcing:

Ich kann mir schon vorstellen, wie gerade ein Raunen durch die Blogosphäre geht. Aber im Gegensatz zu der ein oder anderen Firma, die Arbeitsplätze ins Ausland verlagert, geht es bei uns darum mit externen Dienstleistern aus Deutschland Projekte schneller umzusetzen und dabei noch Geld einzusparen. Obwohl wir bereits mehrfach erfolgreich auf externe IT-ler gesetzt haben, wollen wir das in den nächsten Monaten noch häufiger tun. Im Gegenzug sollen Schulungen und Konferenzbesuche dezimiert werden. Jeder dürfte das damit einhergehende Problem kennen, dass der Teufel immer im Detail steckt und dass das Gelernte sich immer nicht auf das konkrete Problem anwenden lässt. Deshalb finde ich – speziell in Anbetracht der Möglichkeiten mit Skype und Teamviewer – das kurzfristige Hinzuziehen von Spezialisten äußerst hilfreich. Quasi die Just-in-time-Lieferung für die IT Branche. Speziell im Bereich der Softwareentwicklung kann hier massiv an Zeit eingespart werden, wenn man Architekturentscheidungen nochmals von Dritten in Frage stellen oder sich bei sogenannten “Code Smells” Ratschläge geben lässt. Ebenfalls ein gutes Szenario für neue Technologien sind kleine, nicht ausprogrammierte Prototypen, die man dann als Gerüst für den weiteren Ausbau verwenden kann. Inzwischen kann ich behaupten, dass ich ein regelrechter Fan von diesen kleinen, aber regelmäßigen Online Meetings bin.

Mitarbeitergespräche:

Jeden Monat greife ich die Thematik Mitarbeitergespräche als eines meiner Lieblingsthemen in diesem Blog auf. Und wie ich meine zu Recht, da ich es für das wahrscheinlich wertvollste Instrument zur Mitarbeiterführung halte. Für mich ist das Thema immer noch zu selten auf der Agenda von CIOs oder – wenn es denn auf der Agenda steht – ist es für die Meisten eine lästige Pflicht für den Vorgesetzten, die es ohnehin nicht richtig umsetzen. Da ich bereits mehrere Artikel dazu geschrieben habe, werde ich jetzt nicht weiter darauf eingehen. Jedoch sei dieses Mittel jedem CIO, egal bei welcher Abteilungsgröße, ans Herz gelegt.

Nützliche Git und Bash Shell Tipps

In dem Artikel Git Aliase habe ich kurz die “.gitconfig” erwähnt. Da so gut wie jeder Entwickler mehrere Maschinen nutzt und normalerweise gerne mit den gleichen Einstellungen arbeitet, gilt es die benötigten config-Files zu synchronisieren. Neben der zuvor erwähnten Datei sollte man auch noch die “.bashrc” (ebenfalls im Homeverzeichnis des Users) sichern, die die Einstellungen für die Bash Shell enthält. Ich für meinen Teil habe das so gemacht, dass ich die Dateien in einem Verzeichnis, welches ich über alle meine Maschinen synchronisiere, abgelegt und mit hard links darauf referenziert habe. Windows bietet dafür den Befehl “mklink” an. Für die ganz faulen Tipper unter euch, poste ich hier den Inhalt aus meinen 2 config-Files:

.gitconfig

[alias]
    review = log -1 –patch
    unstage = reset head
    aa = add –all
    au = add –update
    s = status
    p = pull
    l = log –oneline -10
    k = !gitk –all & –all &
    aua = !git add –update && git commit –amend –reuse-message=HEAD
    aaa = !git add –all && git commit –amend –reuse-message=HEAD
    amend = commit –amend –reuse-message=HEAD
    aucp = !sh -c ‚git add –update && git commit -m \"$1\" && git push‘ –
    aacp = !sh -c ‚git add –all && git commit -m \"$1\" && git push‘ –

.bashrc

alias g=’git‘

Außerdem will ich noch kurz auf Einstellungen für die Bash Shell verweisen, welche ich sinnvollerweise von Alexander Groß übernommen habe:

imageimage

 

Öffnet dafür die Bash Shell, klickt rechts auf dem Rahmen und geht in Standardwerte. Schaut euch insbesondere die Fensterpuffergröße und die Bearbeitungsoptionen an. Um auch diese Einstellungen einfach auf alle Maschinen zu bringen, könnt ihr euch den Registry-Schlüssel “HKEY_CURRENT_USER\Console” exportieren.

Git Aliase

Wer wie ich nicht immer die gleichen 3 Befehle zum Hinzufügen, Commiten und Pushen von Änderungen zum Git Repository ausführen will, kann sich sogenannte Aliase definieren. Der folgende Screenshot zeigt 2 Aliase, die ich mir in meine benutzerbezogene “.gitconfig” eingetragen habe. Zeile 1 fügt lediglich geänderte Dateien hinzu, während Zeile 2 alle Änderungen hinzufügt:

 image

Hier noch textuell:

!sh -c ‚git add –update && git commit -m \"$1\" && git push‘ –

!sh -c ‚git add –all && git commit -m \"$1\" && git push‘ –

Alternativ sollten auch folgende Zeilen funktionieren:

"!f() { git add –-update; git commit -m \"$1\"; git push; }; f"

"!f() { git add –all; git commit -m \"$1\"; git push; }; f"

 

Beachtet, dass ihr die Aliase nicht über den entsprechenden Git Befehl anlegen solltet, da es sonst ggf. Probleme mit den Hochkommata gibt. Editiert stattdessen die besagte .gitconfig in eurem Homeverzeichnis. Das könnt ihr über den Befehl

vim .gitconfig

machen, wenn ihr euch im richtigen Pfad befindet.

Danke an dieser Stelle an Alexander Groß für seine Hilfe dabei.

%d Bloggern gefällt das: