Archiv für den Monat Juli 2015

Build Server endlich ohne DevExpress

DevExpress ist leider alles andere als vorbildlich, was den Einsatz auf Build Servern angeht. Weder bietet das Unternehmen NuGet Packages, noch lässt sich die Lizenzprüfung auf dem Build Server deaktivieren.

Mit einem kleinen Trick lässt sich aber die Installation umgehen. Hierzu ruft ihr den Installer auf dem Build Server/Agent auf, loggt euch mit euren Daten an dem unten aufgeführten Screenshot ein und brecht nach erfolgreichem Login ab einfach ab.

DevExpress Login Dialog

Damit wurden mehrere Registry Einträge geschrieben, die leider maschinenspezifisch sind. Diese findet ihr hier:

  • HKLM\SOFTWARE\Classes\Licenses378852D-D597-4A32-B6D9-680A16A3CDA6\***
  • HKLM\SOFTWARE\Classes\Licenses\6F0F8269-1516-44C6-BD30-0E90BE27871C\***

Wenn ihr in den Projekten dann DLL-Referenzen aus einem Repository-Verzeichnis verwendet oder euch eigene NuGet Packages baut, benötigt ihr in Zukunft keine Installation mehr. Das gilt auch für Developer, die nicht an der UI mitentwickeln.

Advertisements

Wohin mit den Queries, Repositories und UnitOfWorks in meinen Anwendungsschichten

Am vergangenen .NET Open Space gab es eine Session namens „Repositories oder ORM“. Den Titel fand ich ein wenig unglücklich gewählt. Nutzt man nämlich einen OR-Mapper, so verwendet man implizit Repositories. Zumindest ist das beim Entity Framework der Fall. Dort entspricht der DbContext nämlich der UnitOfWork und die darauf implementierte generische Set-Methode liefert die Repositories zu allen Datenbank-Entitäten.

Grob gesagt sollte pro Geschäftsvorfall (aus Sicht der UI) ein DbContext erzeugt, darauf alle Änderungen und Abfragen ausgeführt und im Anschluss per Commit in einer Transaktion ausgeführt werden. Die Transaktion findet implizit statt, sodass ihr sicher sein könnte, dass entweder alles in die Datenbank geschrieben wurde oder nichts.

Nun wurde die Frage gestellt wie mit Abfragen zu Verfahren ist: Sollte man in allen Layern auf die Repositories zugreifen und dann per LINQ beliebig filtern? Ich bin der Meinung, dass man dies tunlichst unterlassen sollte. Stattdessen nutze ich in der Regel eine der zwei Möglichkeiten (welche sich beide gut zum Testen eigenen):

  • Eine dedizierte Repository-Implementierung, die intern die Abfragen kapselt. Das könnte zum Beispiel die Klasse ‚Rechnungen‘ mit der Methode ‚AlleMitDatumGrößerAls(DateTime datum)‘  sein. Idealerweise mappt das Repository ‚Rechnungen‘ dabei die Entitäten auf Business Objekte. AutoMapper kann in dem Fall viel Schreibarbeit abnehmen.
  • Sollten mehrere Repositories die gleiche Abfrage verwenden, so bietet es sich an die Query in eine eigene Klasse dafür zu extrahieren. Zum Beispiel die Klasse ‚FindeBenutzerMitId‘, welche im Konstruktor die Id übergeben bekommt. Auf der UnitOfWork lässt sich dann die Query z.B. in der Form ausführen: ‚uow.ExecuteQuery(new FindeBenutzerMitId(1))‘. Dafür muss allerdings erst die UnitOfWork um einen solchen Mechanismus erweitert werden. Ich hatte diesen Ansatz vor ein paar Jahren in diesem Video beschrieben.

Leider ist ein Blog Beitrag ungeeignet um ein solch komplexes Thema in der notwendigen Tiefe zu besprechen. Ziel war es daher nur Denkanstöße zu geben und eine Diskussion zu starten. Wer nützliche Ressourcen zu dem Thema hat oder wer andere Ansätze verfolgt, kann diese gerne in die Kommentare schreiben.

Paket vs. NuGet

Am vergangenen .NET Open Space haben einige Teilnehmer nach Erfahrungen zu Paket, der mehr oder weniger neuen Alternative zu NuGet. Mein Statement möchte ich an dieser Stelle für alle festhalten:

Wir haben unser ERP-System mit ca. 70 Projekten vor über 6 Monaten umgestellt und sind sehr zufrieden damit. Warnen muss ich lediglich vor 3 Punkten, die einem bewusst sein müssen:

  • Paket ist nicht in Visual Studio integriert und muss daher über die Kommandozeile ausgeführt werden. Eine Integration ist auch nicht geplant. (Aktualisiert: Ein entsprechendes GitHub Projekt steht zur Verfügung)
  • Jedes NuGet Package, welches die install.ps1 aufruft, funktioniert ggf. nicht richtig nach der Installation mit Paket. Das ist z.B. bei PostSharp der Fall, was ich hier beschrieben habe. Der geneigte Leser möge bitte bei PostSharp für das offene Issue dazu voten.
  • NET Core Projekte erlauben keine Assembly Referenzen mehr, sodass Paket nicht verwendet werden kann.

Die Gründe für einen Abgang von NuGet sind vielfältig und wurden vom Entwicklerteam selbst beschrieben. Mit annähernd allen Problemen räumt Paket auf. Um nur zwei davon zu nennen:

  • Mit dem Updaten von packages werden die Projektdateien nicht mehr verändert. Stattdessen werden lediglich 2 Dateien von Paket selbst aktualisiert. Damit gehören Merge-Konflikte der Vergangenheit an.
  • Einen Abhängigkeitsgraphen bekommt man ebenfalls mitgeliefert. Daraus lässt sich schnell schließen welches Package ein anderes in welcher Version referenziert.

Eine Frage beim Open Space war, ob sich damit auch das gleiche Package in unterschiedlichen Versionen einbinden lässt. Nein, das ist nicht der Fall, was aber nichts mit NuGet oder Paket zu tun hat. Das ist der Tatsache geschuldet, dass ein .NET Prozess eine Assembly nur in genau einer Version laden kann. Zum Lösen dieses Problems bedarf es also immer Binding Redirects. In NuGet 3 soll zumindest ein Feature zum einfachen Konsolidieren unterschiedlicher Versionen eingebaut sein.

Mit NuGet 3 soll ohnehin ein großes Redesign stattfinden, sodass ein näherer Blick darauf ratsam ist. Im Team Blog finden sich einige nützliche Ressourcen.

Ich wollte den Blog Post kurz halten, deshalb habe ich nicht alle Vorteile aufgezählt. Wenn aber ein Leser der Meinung ist, dass noch etwas unbedingt genannt werden soll, dann einfach in die Kommentare posten.

Ist guter Programmcode noch wirtschaftlich

Eine Session am vergangenen .NET Open Space behandelte das Thema Wirtschaftlichkeit. Konkret stellte der Session Hoster an die Teilnehmer die Frage:

Ist es für euch wichtiger die Implementierung technisch möglichst elegant zu machen oder steht die Wirtschaftlichkeit an erster Stelle?

Ich sehe darin 3 mögliche Antworten:

  • Gerade durch die technische Eleganz steigt die Wirtschaftlichkeit, z.B. weil das Produkt bessere Performance als Konkurrenzprodukte hat.
  • Beides steht im Einklang. Würde für die Implementierung nicht die notwendige Sorgfalt aufgewendet werden, müsste das Produkt früher oder später recycelt und gänzlich neu entwickelt werden.
  • Die Wirtschaftlichkeit in Form von Manntagen zum Zwecke einer „besseren“ Umsetzung wird vermindert.

Speziell zu letztem Punkt habe ich eine ganz eigene Einstellung, zu welchem ich gerne eure Meinung hören würde. Meines Erachtens gilt es nämlich zuerst ganz andere Stellen im Produktenwicklungsprozess zu optimieren. Hierzu einige Beispiele aus meiner Praxiserfahrung:

  • Es werden Anforderungen aufgenommen, welche keinen Nutzen bringen. Diesen kommt man recht einfach auf die Schliche, indem man dem Verantwortlichen 5x die Frage ‚Warum‘ stellt. Ich schätze, dass zw. 5-10% der Anforderungen, die von den Fachabteilungen eingebracht und umgesetzt werden, keinen praktischen Nutzen erfüllen.
  • Die Priorisierung von Feature-Wünschen ist nicht gemäß deren Business Values. Wenn nicht die Dinge zuerst implementiert werden, die den höchsten Nutzen bringen und dabei das niedrigste Risiko und den geringsten Aufwand aufweisen, dann leidet die Wirtschaftlichkeit (Ausnahme: Bei einem neuen Produkte sollten die mit dem höchsten Risiko zuerst umgesetzt werden).
  • Es werden mehr neue Anforderungen aufgenommen, als umgesetzt werden können. Wenn in einem Jahr 200 Einträge im Issue Tracking System aufschlagen, aber nur 100 umgesetzt werden können, dann wurde definitiv Geld in Form von Arbeitszeit verbraten.
  • Es wird nicht die notwendige Sorgfalt in die Ausarbeitung von Anforderungen gesteckt. In einem Pluralsight Video bin ich kürzlich auf die Aussage gestoßen, dass 50-70% der Entwicklungskosten auf schlechte/falsche Anforderungen zurückzuführen sind.
  • Bei manchen Anforderungen kann erheblich viel Entwicklungszeit eingespart werden, wenn bestimmte Aspekte, auf die auch der Anwender verzichten kann, weggelassen werden. Hierbei sind die Entwickler gefragt, nachzuhaken, ob sich das Feature eventuell an der ein oder anderen Stelle reduzieren lässt.
  • Kommunikation: Der Wert einer guten Kommunikation lässt nicht beziffern.
  • Automatisierte Prozesse für sich wiederholende Aufgaben, z.B. Continuous Deployment. Das spart täglich Geld!

Das sind nur ein paar Punkte, bei denen ich als erstes Hand anlegen würde! Wie seht ihr das?

%d Bloggern gefällt das: