Surface Pro 3 – Microsoft hat geliefert! 28.08.2014

Werner Franz
Werner Franz, Vorstand

Seit heute Vormittag halte ich mit dem Surface Pro 3 das professionelle Device in den Händen, das ich schon mit der ersten Surface-Ankündigung erwartet hatte:

      • Professionelles Windows 8-Arbeitsgerät, als Tablet Couch-fähig
      • Leistungsstark (Intel Core 17, 8 GB, 512 GB SSD)
      • Absolut wertiges, edles Design
      • Leicht und kaum höher als ein Schreibblock
      • Cooler Sitft, der auf Knopfdruck OneNote öffnet
      • Abnehmbare Tastatur im SDX corporate blau
      • Dazu eine Surface Arc Touch Mouse

Fazit: Perfekt. Endlich die gelungene Symbiose von Laptop und Tablet mit Coolness-Faktor.

Surface-IIISurface-III-cSurface-III-b

Ach ja: Infos zu Windows 8 App Development gibt’s hier

Share |

Top 10 Fehler–#11: Neglecting FxCop/Static Code Analysis 27.08.2014

Alexander Jung
Alexander Jung, Chief eXpert

Dies ist Teil 12 der kleinen Serie, die ich als Kommentar zum Blog-Beitrag Top 10 Mistakes that C# Programmers Make begonnen habe.

Und mittlerweile bin ich bei den Themen angekommen, die mir in der Liste noch fehlen. 11 von 10 ist also kein Fehler ;-)…

 

AJ’s Common Mistake #11: Neglecting FxCop/Static Code Analysis

Es zieht sich wie ein roter Faden durch viele von Patrick’s “Common Mistakes”, wurde aber von ihm nie explizit adressiert: FxCop bzw. die in Visual Studio eingebaute Variante Code Analysis würde helfen!

Der Compiler kann Warnungen liefern wenn es um typische Fallen auf Sprachebenen geht, leere Anweisungen weil ein Semikolon zu viel gesetzt wurde und ähnliches. Aber sobald es um die korrekte Verwendung von Methoden geht, um Code-Idiome und Patterns, um Prüfungen von Randbedingungen etc., schlägt die Stunde von Werkzeugen zur statischen Code-Analyse, speziell FxCop.

Merker: Es gibt keinen Grund, FxCop nicht einzusetzen! Aber viele Gründe das zu tun!

Man sollte das auch von Anfang an tun; FxCop einzuschalten wenn ein Projekt schon einige Zeit entwickelt wurde führt häufig zu einer Flut von Fehlermeldungen.

Worüber man durchaus zumindest kurz nachdenken sollte ist die Frage, wie FxCop eingesetzt werden soll, sprich mit welchen Regeln. Selbst Microsoft bietet von sich aus schon unterschiedliche Regel-Sets an. Und in der Voreinstellung ist Microsoft hier (leider) sehr zögerlich. Die voreingestellten Managed Recommended Rules kann man sich nach meiner Erfahrung auch sparen. Selbst klassische Fehler, wie Enums ohne 0-Wert werden damit nicht geprüft. Andererseits sind “Microsoft All Rules” dem einen oder anderen dann vielleicht doch etwas zu viel des Guten. Bleibt die Definition eines eigenen Regelsets. Genau das wird aber seit Visual Studio sehr gut unterstützt.

Und wem das noch nicht reicht, der kann das Thema auch noch weiter ausreizen:

Share |

Top 10 Fehler: Wrap-Up–erstmal… 22.08.2014

Alexander Jung
Alexander Jung, Chief eXpert

Dies ist Teil 11 der kleinen Serie, die ich als Kommentar zum Blog-Beitrag Top 10 Mistakes that C# Programmers Make begonnen habe.

Patricks Liste ist ja schon ziemlich umfangreich und in weiten Teilen (wenn auch nicht in allen Aspekten) kann ich mich damit anfreunden.

 

Hier nochmal die Übersicht und meine Wertung:

  1. Using a reference like a value or vice versa Enttäuschtes Smiley
    – Inhaltlich korrekt, aber nach meiner Erfahrung kein “common mistake”.
     
  2. Misunderstanding default values for uninitialized variables Smiley
    – Das dargestellte Problem ist eher akademisch als praxisrelevant, aber es gibt einen nahen Verwandten, den man erwähnen sollte…
     
  3. Using improper or unspecified string comparison methods Smiley mit geöffnetem Mund
    – Full Ack!
     
  4. Using iterative (instead of declarative) statements to manipulate collections Smiley mit geöffnetem Mund
    – Full Ack! Plus Ergänzungen!
     
  5. Failing to consider the underlying objects in a LINQ statement Smiley mit geöffnetem Mund
    – Full Ack! Und noch viel zu harmlos dargestellt.
     
  6. Getting confused or faked out by extension methods Enttäuschtes Smiley
    – Inhaltlich korrekt, aber nach meiner Erfahrung kein “common mistake”.
      
  7. Using the wrong type of collection for the task at hand Verärgertes Smiley
    – Problem erkannt, aber leider bei der Lösung danebengegriffen…
     
  8. Neglecting to free resources Smiley mit geöffnetem Mund
    – Full Ack! Der Klassiker…
     
  9. Shying away from exceptions Smiley mit geöffnetem Mund
    – Full Ack!
     
  10. Allowing compiler warnings to accumulate Smiley mit geöffnetem Mund
    – Full Ack!

Und auch mit seinem Wrap-Up kann ich mich anfreunden:

C# is a powerful and flexible language with many mechanisms and paradigms that can greatly improve productivity.  As with any software tool or language, though, having a limited understanding or appreciation of its capabilities can sometimes be more of an impediment than a benefit, leaving one in the proverbial state of “knowing enough to be dangerous”.

Wer mich kennt, weiß dass das ein gutes Ergebnis ist Zwinkerndes Smiley.

Auf der anderen Seite: Wenn ich mir die Liste insgesamt anschaue, dann fehlen mir da noch ein paar Dinge. Also wird das nicht der letzte Beitrag dieser Reihe sein…

Share |

Top 10 Fehler–#10: Allowing compiler warnings to accumulate 18.08.2014

Alexander Jung
Alexander Jung, Chief eXpert

Dies ist Teil 10 der kleinen Serie, die ich als Kommentar zum Blog-Beitrag Top 10 Mistakes that C# Programmers Make begonnen habe.

Heute zum Thema…

 

Common Mistake #10: Allowing compiler warnings to accumulate

Der (zugegeben etwas pathologische) Quellcode für folgende Ausgabe umfasst kaum ein dutzend Zeilen Code:

   1: 1>D:\Test\ConsoleApplication1\ConsoleApplication1\Program.cs(88,17,88,18): warning CS0642: Possible mistaken empty statement
   2: 1>D:\Test\ConsoleApplication1\ConsoleApplication1\Program.cs(84,17,84,19): warning CS0219: The variable 'i3' is assigned but its value is never used
   3: 1>D:\Test\ConsoleApplication1\ConsoleApplication1\Program.cs(91,13,91,27): warning CS0162: Unreachable code detected
   4: 1>d:\Test\ConsoleApplication1\ConsoleApplication1\Program.cs(84): warning CA1804: Microsoft.Performance : 'Program.Main(string[])' declares a variable, 'i3', of type 'int', which is never used or is only assigned to. Use this variable or remove it.
   5: 1>d:\Test\ConsoleApplication1\ConsoleApplication1\Program.cs(85): warning CA1804: Microsoft.Performance : 'Program.Main(string[])' declares a variable, 'i4', of type 'int', which is never used or is only assigned to. Use this variable or remove it.
   6: 1>d:\Test\ConsoleApplication1\ConsoleApplication1\Program.cs(96): warning CA1811: Microsoft.Performance : 'Program.TestDisposable()' appears to have no upstream public or protected callers.

Man kann sich ausmalen, wie sich das in einem größeren Projekt auswirkt. Und wie “hilfreich” dieser Ausgabe für Entwickler ist, die neu zum Team stoßen und die Anwendung das erste mal übersetzen.

Patrick hat damit zurecht ein Problem:

Remember, the C# compiler gives you a lot of useful information about the robustness of your code… if you’re listening. Don’t ignore warnings.

Warnungen dass eine Variable nicht verwendet wurde, dass Code nicht erreichbar ist und ähnliches, sind keine esoterischen Weisheiten, sondern ernstzunehmende Hinweise.

Patrick geht noch einen Schritt weiter…

They usually only take a few seconds to fix, and fixing new ones when they happen can save you hours. Train yourself to expect the Visual Studio “Error List” window to display “0 Errors, 0 Warnings”, so that any warnings at all make you uncomfortable enough to address them immediately.

… ohne das allerdings ausreichend zu begründen.

Was ist denn mit Warnings, die man im Grunde einfach zur Kenntnis nehmen könnte? “Ja, ich hab’s mir angeschaut, das ist OK so.” Sind die damit nicht erledigt?

Nein, sind sie nicht. Nicht solange sie vom Compiler gemeldet werden. 20 Warnungen dieser Kategorie zwingen mich regelmäßig dazu, wieder darüber nachzudenken. Sie zwingen neue Kollegen dazu, die gleichen Überlegungen anzustellen. Und sie sorgen dafür, dass die 21. Warning, die seit einiger Zeit auftaucht, im Rauschen untergeht und deshalb nicht behoben wird – obwohl sie womöglich unmittelbare Aufmerksamkeit verdient hätte.

Genau deshalb gilt in meinen Projekten eine strikte no-warnings-policy!

Und wenn man den Code nicht ändern will?

  • Für Compiler-Warnungen gibt es entsprechende Pragmas, mit der man die Warnung gezielt abschalten kann – womit man auch gleichzeitig dokumentiert, das man sich damit auseinandergesetzt hat und weiß, was man tut.
  • Für FxCop-Warnungen gibt es im Visual Studio einfache Möglichkeiten das gleiche zu tun.
  • StyleCop habe ich lange abgelehnt, weil mir genau diese Möglichkeit gefehlt hat. Aber auch hier wird die Situation besser.

 

Wovon ich übrigens kein großer Freund bin, ist die Option “Warnings as errors”. Während der Entwicklung – also während ich gerade Code produziere – sind Warnings völlig normal. Es macht keinen Sinn, formale Anforderungen für halbfertigen Code durchsetzen zu wollen, das behindert mich nur in meiner Arbeit.

Share |

SQL CLR: Integrationsmerkmale und Einsatzempfehlungen 13.08.2014

Frank Landgraf
Frank Landgraf, Principal BI eXpert

Es ist schon lange her, genauer gesagt im Jahr 2005, als Microsoft mit SQL CLR (dem Quasi-Nachfolger von Extended Stored Procedures) die Nutzung von .NET innerhalb des SQL Servers eingeführt hat. In diesem Artikel möchte ich hauptsächlich darauf eingehen, was Microsoft konkret hinsichtlich der CLR Integration in SQL Server getan hat und was man bei der Nutzung von Assemblies innerhalb des SQL Servers im Hinterkopf haben sollte.

Im persönlichen Projektalltag habe ich den Einsatz von eigenen Assemblies auf Produktionssystemen (mal abgesehen von Open-Source Projekten wie dem Analysis Services Stored Procedure Project) noch nicht so häufig gesehen. Das liegt sicher zum einen an restriktiven Vorschriften hinsichtlich des Server-Betriebsmanagements, aber möglicherweise auch an einer gewissen Vorsicht. Denn einen sporadischen Speicherfehler in einem Produktionssystem zu finden, kann eine heikle Angelegenheit sein. Schauen wir uns also kurz an, wie es um das Thema Security steht.

Microsoft hat sich doch einige Mühe gemacht, die Ausführung von .NET Code innerhalb einer SQL Server Instanz so sicher und zuverlässig wie möglich zu machen. Für die Codezugriffsberechtigungen SAFE und EXTERNAL_ACCESS gibt es eine Assemblyvalidierung beim Erstellen mit CREATE ASSEMBLY, bei der IL-Code geprüft wird und die garantieren soll, dass der Code typsicher ist und bestimmten Sicherheitsrichtlinien entspricht (Näheres dazu hier). Anderenfalls wird das CREATE ASSEMBLY-Statement mit einem Fehler abgebrochen. Im UNSAFE-Modus dagegen, darf auch Unmanaged Code enthalten sein und der Zugriff auf Systemressourcen ist nur durch die Berechtigungen des Aufrufers selbst beschränkt, aber nicht durch SQL Server.

Innerhalb des .NET-Frameworks wurden Methoden, die aus SQL Server Sicht hinsichtlich der Sicherheit problematisch sind, mit HostProtection-Attributen (HPA) versehen. Nutzt man innerhalb der eigenen Assembly eine solche Methode, wird je nach Codezugriffsberechtigung eine HostProtectionException geworfen. Im Folgenden Beispiel hatte ich ExternalAccess verwendet und die BeginExecuteNonQuery-Methode des SqlCommand aufgerufen.

SQLClr_Threading.

Hier noch der zugehörige Methodenausschnitt aus der System.Data.SqlClient.SqlCommand-Klasse:

image

Wollte man BeginExecuteNonQuery trotzdem einsetzen, kann man das natürlich tun. Allerdings muss dann die Assembly im UNSAFE-Modus bereitgestellt werden. Eine Liste der nicht erlaubten HPA gibt es hier.

Ein weiteres Sicherheitsfeature ist, dass SQL Server keine Assemblies aus dem Global Assembly Cache (z.B. mit Assembly.Load("....")) oder von einer sonstigen Stelle lädt, sondern nur diejenigen, die mit CREATE ASSEMBLY in SQL Server als Objekt in binärer Form deklariert wurden. Das Einbinden als BLOB hat zusätzlich den Vorteil, dass beim BACKUP und RESTORE die Assembly mitberücksichtigt wird, d.h. nach dem Wiederherstellen ist auch der Assemblycode wieder verfügbar.

Beim Erstellen einer Assembly in SQL Server wird diese als AppDomain (je Datenbank und Assembly-Eigentümer eine) isoliert. Hat man also 2 Assemblies in einer Datenbank mit 2 unterschiedlichen Assembly-Eigentümern, so werden diese auch in 2 getrennte AppDomain-Container überführt. Somit lässt sich auch der Extrem-Fehlerfall (Entladen der AppDomain) in gewisser Weise steuern. Generell empfiehlt es sich, Funktionen zusätzlich auch nach Codezugriffsberechtigung zu strukturieren. D.h. hat man eine Menge X von Funktionen, die im SAFE-Modus laufen können und eine Menge Y, die auf Ressourcen außerhalb von SQL Server zugreifen, bietet es sich an, diese auch in 2 Assemblies mit SAFE bzw. EXTERNAL_ACCESS-Berechtigungen auszulagern.

Um die Betriebssicherheit eines Servers zu wahren bzw. zumindest eine weitere Hürde nehmen zu müssen, dürfen nur Datenbankadministratoren mit sysadmin- bzw. serveradmin-Berechtigungen die Ausführung von Assemblies erlauben. Um sie erstellen zu dürfen, braucht man mindestens CREATE ASSEMBLY-Berechtigungen. Mindestens deshalb, weil das nur auf solche im Modus SAFE zutrifft. Für das Sicherheitslevel EXTERNAL_ACCESS sind es schon EXTERNAL_ACCESS-Berechtigungen und für UNSAFE führt kein Weg am Systemadministrator (sysadmin-Rolle) vorbei.

Zusätzlich gibt es noch eine Failure escalation policy, die beispielsweise beim Beenden einer SQL Session mit dem Kill-Befehl dafür sorgt, dass der jeweilige Thread sauber beendet wird. Sofern der Thread jedoch in einer kritischen Region besteht und dort ein Lock auf einem Objekt gehalten wird, entlädt SQL Server einfach die komplette AppDomain, sodass ein sauberer Zustand gewährleistet bleibt. Das Entladen der AppDomain kann insbesondere bei Situationen auftreten, in denen SQL Server der Speicher ausgeht (Memory Pressure).

Performance

SQL Server unterscheidet sich als Laufzeithost doch in einem zentralen Punkt besonders von anderen Konkurrenten wie Oracle oder IBM DB2. Während Oracle und DB2 CLR-Code in einem externen Prozess ausführen, geschieht dies bei SQL Server im Serverprozess selbst. Unter Sicherheitsaspekten könnte man natürlich argumentieren, dass die Isolation bei DB2 oder Oracle ein höheres Maß an Sicherheit (zumindest was den Datenbankhost angeht) gewährt, jedoch resultiert aus der Out-Of-Process Ausführung” auch der Nachteil, dass die Performance nicht so optimal ist, wie sie sein könnte und sich ferner auch einige andere Seiteneffekte (wie z.B. Sichtbarkeit von temporären Tabellen oder andere Transaktionsisolationlevel) ergeben.

Durch die Ausführung im SQL Server Hostprozess wird bei bestimmten Operationen eine sehr hohe Leistung erreicht. Insbesondere zeilenbasierte Operationen werden in SQL CLR wesentlich schneller ausgeführt als in Transact-SQL. Sobald jedoch mengenbasierte Aktionen ins Spiel kommen, ist T-SQL deutlich überlegen. Bei CLR Skalarfunktionen (ohne Datenzugriff via SqlConnection) entsteht ein wesentlich geringerer Call-Overhead als bei den Pendants in T-SQL. Sind Datenzugriffe im Spiel (z.B. mit der ContextConnection) kann man grob sagen, dass T-SQL 2-3x schneller ist, weil dort ggf. Daten im Bufferpool liegen und somit wesentlich schneller darauf zugegriffen werden kann.

Wann sollte man die Nutzung von .NET-Assemblies im SQL Server in Erwägung ziehen?

Die Antwort ist, wie so oft..."It depends!".

Bei rechenintensiven oder zeilenweisen Operationen kann der Performancegewinn mit CLR-Code enorm sein. Die charmante Erweiterung von Funktionalität, die nicht standardmäßig in T-SQL verfügbar ist, aber auch der Zugriff auf externe Ressourcen (z.B. Dateien) können den Einsatz von SQL CLR ebenfalls rechtfertigen.

Bei mengenbasierten Operationen sollte man dann aber doch zu (T-)SQL greifen.

Bei Prozessen, die eigentlich in die Middle-Tier-Schicht gehören, sollte man ebenfalls von einer Integration in die Datenzugriffsschicht Abstand nehmen.

Es gibt sicher Situationen, in denen die Entscheidung T-SQL vs. SQL CLR nicht eindeutig abzugrenzen ist. In solchen Fällen ist es empfehlenswert, die beiden Methoden einfach gegenüberzustellen und unter Berücksichtigung des Assembly-Management-Overheads die Art der Implementierung abzuwägen.

Fazit

SQL CLR dient bei genauer Betrachtung und unter Berücksichtigung der Vor- und Nachteile als sinnvolle Erweiterung der nativen Funktionalität von T-SQL. Wenn es mit Maß eingesetzt wird, können Business Anwendungen in bestimmten Szenarien gut davon profitieren.

PS: Unter http://www.sqlsharp.com findet man bereits eine Bibliothek mit allen möglichen Funktionen, die mit SQL CLR umgesetzt wurden und ggf. (nach einem Review!) eingesetzt werden können.

Quellen

1. http://msdn.microsoft.com/en-us/magazine/cc163716.aspx (Critical Regions)
2. http://msdn.microsoft.com/en-us/library/ms131089(v=sql.110).aspx (inkl. Unterseiten)
3. http://www.sqlskills.com/blogs/bobb/category/sqlclr/ (inkl. Unterseiten)

Share |

Top 10 Fehler–#9: Shying away from exceptions 08.08.2014

Alexander Jung
Alexander Jung, Chief eXpert

Dies ist Teil 9 der kleinen Serie, die ich als Kommentar zum Blog-Beitrag Top 10 Mistakes that C# Programmers Make begonnen habe.

Heute zum Thema… Exceptions!

 

Common Mistake #9: Shying away from exceptions

Ich kenne erfahrene Entwickler, die mit Exceptions lieber nichts zu tun haben wollen, weil sie nicht wissen, wie sie damit umgehen sollen. Damit meine ich nicht, dass die Grundlagen von try/catch/throw nicht bekannt wären; vielmehr machen sich viel zu wenig Entwickler Gedanken darüber, wann sie Exceptions werfen, wo sie sie fangen, warum sie das tun, und was dann damit passieren soll.

Ergo ist eine typische Verhaltensweise, Exceptions möglichst schnell plattzumachen oder Code von vorne herein so zu schreiben, das es erst gar nicht zu einer Exception kommt. Was genau das ist, was Patrick in seinem Mistake #9 ankreidet:

Some programmers are so “exception adverse” that they automatically assume the method that doesn’t throw an exception is superior.

Falls Patrick mit seiner Nummerierung eine Gewichtung der Fehler verbindet, dann wäre dieser Punkt bei mir definitiv auf einem der vorderen Plätze.

 

Tatsächlich gibt es sogar wohlgemeinte Ratschläge (der Weg zur Hölle… . Sorry.) in dieser Richtung: Lance Hunt gibt in seinem weit verbreiteten C# Coding Standards Document (alternativer Link) die folgende Empfehlung:

23. Avoid direct casts. Instead, use the “as” operator and check for null.
Example:
object dataObject = LoadData();
DataSet ds = dataObject as DataSet;
if(ds != null)
{…}

Patricks Empfehlung ist da die weitaus bessere:

However, it is incorrect to assume that TryParse is therefore necessarily the “better” method.  Sometimes that’s the case, sometimes it’s not. That’s why there are two ways of doing it. Use the correct one for the context you are in, remembering that exceptions can certainly be your friend as a developer.

Oder um es noch etwas deutlicher zu formulieren:

  • Man verwendet as, TryParse(), FirstOrDefault(), etc., wenn es im Sinne der Programmlogik absolut legal und erwartungskonform ist, dass der Aufruf auch fehlschlagen kann. Das ist immer dann der Fall wenn andere Typen zulässig sind oder wenn zu parsende Daten von außen kommen, etwa aus der Konfiguration, und ähnliches.
  • Man verwendet Casts, Parse(), First(), etc., wenn die Programmlogik ein Fehlschlagen eigentlich nicht zulässt, wenn das also ein Symptom für einen echten Programmierfehler ist. Solche Konstellationen sollten nicht durch irgendeine Fallback-Logik unter den Teppich gekehrt werden, da sie im schlimmsten Fall Folgefehler nach sich ziehen und zu korrupten Daten führen können.

Bezüglich Casts vs. as kommt noch ein weitere Aspekt hinzu: Der Unterschied zwischen den beiden ist tatsächlich größer, als null vs. Exception. Casts führen ggf. Type Conversions durch, während ein as damit nicht viel anfangen kann. Und bei Value Types ist as nicht mal zulässig.

Simples Beispiel:

   1: var i1= 3.5 as int; // Compilerfehler
   2: var i2= (int)3.5; // Typkonversion

Im Grunde gilt wie so oft: “One size fits all” funktioniert nicht. Man kommt nicht umhin den Einzelfall zu betrachten und Pauschalaussagen schaden mehr als sie nutzen.

Share |

Wir brauchen Verstärkung: Service Delivery Manager gesucht! 05.08.2014

Svenja Henß
Svenja Henß, Senior Assistant

Das SDX Team wächst und wir sind auf der Suche nach einem Service Delivery Manager für unseren Standort in Frankfurt.

Du kommst aus der Software Entwicklung, hast bereits als Consultant bzw. Projektleiter gearbeitet und möchtest den nächsten Schritt gehen? Du spielst gedanklich bereits mit einer neuen Herausforderung?

Dann solltest du dir unser Jobangebot näher anschauen:

Service-Delivery-Manager

>Hier< geht es direkt zu unserer Anzeige auf Stepstone.

Share |

Top 10 Fehler–#8: Der Evergreen: IDisposable 01.08.2014

Alexander Jung
Alexander Jung, Chief eXpert

Dies ist Teil 8 der kleinen Serie, die ich als Kommentar zum Blog-Beitrag Top 10 Mistakes that C# Programmers Make begonnen habe.

Heute zum Thema… das älteste .NET-Problem überhaupt!

 

Common Mistake #8: Neglecting to free resources

Als Microsoft das .NET Framework vorstellte (standing ovations der COM-geplagten Entwickler auf der PDC 2000) und den Entwicklern (meist mit einer C++-Historie) eine erste Version zur Verfügung stellte, war dies der vielleicht am heißesten diskutierte Punkt in den entsprechenden Foren: Kein Destruktor! Sakrileg!

Tatsächlich war in der ersten Version IDisposable noch gar nicht vorhanden und entstand wohl erst aufgrund des vehementen Feedbacks aus der Entwicklergemeinde. (Microsoft tendiert bei neuen Dingen leider immer zu etwas Betriebsblindheit gegenüber den Nachteilen.)

Danach hat Microsoft aber ziemlich schnell die Kurve bekommen und unterstützt IDisposable et al. inzwischen mit einem eigenen Schlüsselwort in C#, Guidelines, Framework-Klassen und einer ganzen Reihe von FxCop-Rules (CA1001, CA1049, CA1063, CA1816, CA1821, CA2000, CA2004, CA2202, CA2213, CA2215, CA2216, CA2220, CA2221).

Dazu kommt noch eine unüberschaubare Anzahl von Blogbeiträgen.

 

Und trotzdem bleibt das ein regelmäßig auftretendes Problem, zum Beispiel wenn mal wieder eine Datei nicht sauber geschlossen wird oder ein Objekt Referenzen auf andere Objekte hält, ohne zu berücksichtigen, dass diese disposable sein könnten.

Patrick hat deshalb mit seinem Hinweis völlig recht:

If you are creating and disposing of an object within the context of a single code block, it is basically inexcusable to forget to call Dispose(), because C# provides a using statement that will ensure Dispose() gets called no matter how the code block is exited (whether it be an exception, a return statement, or simply the closing of the block).  

Auch wenn er trotz des C++-Blickwinkels nicht wirklich die verstanden hat, was es mit den diversen Begrifflichkeiten in C, C++ und .NET auf sich hat… (sic!)

Share |

Advanced T-SQL: WITH TIES 29.07.2014

Matthias Pohl
Matthias Pohl, IT-Consultant
Office Days sind bei der SDX AG monatlich etablierte Veranstaltungen, bei denen sich alle Mitarbeiter in den firmeninternen Räumlichkeiten zusammenfinden. Neben der Förderung und Stärkung der eXpert-Community dienen diese Events auch zum Informationsaustausch und Knowhow-Transfer zu diversen Themen zwischen den Kollegen.
An einem der letzten SDX Office Days habe ich eine Breakout-Session zum Thema “Advanced T-SQL” gehalten, bei dem ich einige spezielle Features der Abfragesprache T-SQL zeigen durfte. Zu diesem Vortrag gehörte u.a. auch die Vorstellung der “WITH TIES”-Option, welche zwar schon seit langer Zeit fester Bestandteil von T-SQL ist, zu meiner großen Überraschung aber dem ein oder anderen Kollegen noch nicht bekannt war.
Im Rahmen dieses Artikels soll gezeigt werden, dass auch im Bereich der Datenbank-Programmierung mit T-SQL beim Vergleichen und Sortieren von Werten bestimmte Bedingungen berücksichtigt werden müssen. Insbesondere wenn mit “SELECT TOP [N]”-Abfragen eine fixe Anzahl von Datensätzen aus der Datenbank auslesen werden, sollte bei mehreren möglichen Abfrageergebnissen (zumindest etwas) Vorsicht geboten sein.

Vorsicht bei SELECT TOP N

Folgende T-SQL-Syntax erlaub es, eine feste Anzahl von Datensätzen, welche nach bestimmten Eigenschaften sortiert sind, aus einem Datenbank-Objekt (z.B. Tabellen oder Views) abzufragen:
 
   1:  SELECT TOP [positivIntValue] [Column1], ... , [ColumnN]
   2:  FROM [DbObject]
   3:  ORDER BY [SortPredicate1] [ASC/DESC], ..., [SortPredicateN] [ASC/DESC]

So weit so gut: Doch was ist, wenn es mehrere mögliche Ergebnisse für ein solches “SELECT TOP N”-Statement mit entsprechendem Sortierkriterium gibt? Ab dem Absetzen des SQL-Befehls ist das Abfrageergebnis von der zugrundenliegenden Datenbank-Implementierung abhängig und kann nicht weiter beeinflusst werden.
Dass dieser Umstand durchaus Probleme mit sich bringen kann, soll folgende Gesamtmenge von günstigen (Klein-)Fahrzeugen Smiley in einer einfachen Tabelle dienen:
 
image_thumb9_thumb
Wenn die drei teuersten Autos ermittelt werden sollen, bietet sich zunächst folgendes T-SQL-Statement an:
 
   1:  SELECT TOP 3 
   2:  Color, Name, Price 
   3:  FROM TblCars 
   4:  ORDER BY Price DESC;
 
Das Problem, bei dieser Abfrage ist, dass sie für die Gesamtmenge mit den angegebene  5 Autos kein eindeutiges Ergebnis zurückliefern kann. Beide der folgenden Abbildungen enthalten Objekte mit den gesuchten Kriterien und stellen somit gültige Ergebnisse der vorherigen SQL-Abfrage dar:
 
image_thumb6
 
oder
image_thumb7

WITH TIES-OPTION

Wenn es mehrere Einträge gibt, die dem angegebenen Sortierkriterium entsprechen und bei der Abfrage mit Berücksichtigung finden sollen, bietet sich die “WITH TIES”-Option mit folgender Syntax an:
 
   1:  SELECT TOP [positivIntValue] 
   2:  WITH TIES [Column1], ..., [ColumnN]
   3:  FROM [DbObject]
   4:  ORDER BY [SortPredicate1] [ASC/DESC], [...], [SortPredicateN] [ASC/DESC]

Die drei teuersten Wagen aus dem aktuellen Beispiel können mit folgender T-SQL-Formulierung ermittelt werden:
 
   1:  SELECT TOP 3 
   2:  WITH TIES 
   3:  Color, Name, Price 
   4:  FROM TblCars
   5:  ORDER BY Price DESC;

Das Ergebnis dieser Abfrage liefert, wie die folgende Abbildung zeigt, alle Datenbankeinträge, die dem angegebene Sortierkriterium entsprechen entsprechen. Der Vorteil hierbei ist, dass insbesondere auch doppelte Einträge berücksichtigt werden. Außerdem ist dieses Abfrageergebnis komplett deterministisch und eindeutig wiederholbar.
 
image

Zusammenfassung

Natürlich hängt es immer vom konkreten Anwendungsfall ab, wie mehrere mögliche Abfrageergebnissen behandelt werden sollen. Wenn es aber darum geht, mehre alle Datensätze mit gleichen Sortierbedingungen zu ermitteln und man sich nicht auf die Willkür der eingesetzten Datenbank-Technologie verlassen will, dann ist die WITH TIES-Option eine valide Empfehlung.
Als praktische Anwendungsszenarien aus dem realen Alltag dienen beispielsweise Sportveranstaltungen wie die olympischen Spiele . Bei solchen Sport-Events muss im Gedanken an das sportliche Fairplay immer eine Antwort bzw. klare Regelung gefunden werden, wenn darum geht, gleiche Platzierungen entsprechend zu honorieren.

Quelle

Share |

Top 10 Fehler–#7: Collection-Klassen 25.07.2014

Alexander Jung
Alexander Jung, Chief eXpert

Dies ist Teil 6 der kleinen Serie, die ich als Kommentar zum Blog-Beitrag Top 10 Mistakes that C# Programmers Make begonnen habe.

Heute zum Thema… (immer noch ein bisschen LINQ…)

 

Common Mistake #7: Using the wrong type of collection for the task at hand

Yup, das ist eine Sache, die ich auch immer wieder ärgerlich finde. Allerdings aus anderen Gründen, als Patrick:

C# provides a large variety of collection objects, with the following being only a partial list:
Array, ArrayList, BitArray, BitVector32, Dictionary<K,V>, HashTable, HybridDictionary, List<T>, NameValueCollection, OrderedDictionary, Queue, Queue<T>, SortedList, Stack, Stack<T>, StringCollection, StringDictionary.

Dabei hat er sogar Typen unterschlagen, die regelmäßig Probleme machen: CollectionBase und ICollection bzw. Collection<T> und ICollection<T>.

Und er scheint diese Inflation für eine gute Sache zu halten:

While there can be cases where too many choices is as bad as not enough choices, that isn’t the case with collection objects. The number of options available can definitely work to your advantage.  Take a little extra time upfront to research and choose the optimal collection type for your purpose.  It will likely result in better performance and less room for error.

Und kommt zu einer Empfehlung, mit der ich mich nicht anfreunden kann:

If there’s a collection type specifically targeted at the type of element you have (such as string or bit) lean toward using that one first. The implementation is generally more efficient when it’s targeted to a specific type of element.

Offen gestanden ist mir das etwas zu kurzsichtig.

 

Das Thema Collections krankt an zwei Phänomenen:

  • Historischer Wildwuchs
  • Vermischung von Konzepten

Das hat u.a. dazu geführt, dass das .NET Framework – sonst immer ein guter Indikator – und die Empfehlungen von Microsoft selbst zu dieser Frage nur Chaos als Antwort bieten.

Historischer Wildwuchs

.NET 1.0 hatte keine Unterstützung für Generics. Trotzdem brauche man natürlich Collections, und so entstanden Klassen, die mit Objects arbeiten, sowie spezialisierte Ergänzungen für bestimmte Typen und Anforderungen.

Mit .NET 2.0 kamen Generics, einschließlich der entsprechenden Typen für Collections. Und damit auch die Empfehlung, diesen den Vorzug zu geben:

If you’re using the .NET Framework 2.0 or later, using the old non-generic collections is strongly discouraged. (MSDN Magazine)

Natürlich waren zu diesem Zeitpunkt schon wesentliche Teile des .NET Frameworks in Stein gemeißelt. Ergo kommt man auch heute oft nicht an NameValueCollection oder anderen Klassen vorbei.

Vermischung von Konzepten

Von Anfang an gab es zwei konzeptionelle Zusammenhänge in denen Collections eine Rolle spielen:

  1. Als Implementierung von Datenstrukturen
  2. Als Schnittstelle zu den Datenstrukturen

Diese Trennung ist nun nicht gerade neu. Die Collection-Klassen in der Collection Class Library von IBM (Teil der IBM Open Class Library) haben Schnittstelle (Stack, Queue, ec.) und die eigentliche Implementierung (Array, Linked List, etc.) über Templates zusammengebaut – vor über einem viertel Jahrhundert. Die STL erreicht eine Trennung der Konzepte über Container-Klassen und Iteratoren. 

Der Versuch, gleiches im .NET Framework zu verankern ist nur teilweise gelungen. Einerseits gab es von Anfang an ICollection als Schnittstelle und CollectionBase als Standard-Implementierung, die auch oft verwendet wurden (CollectionBase Ableitungen, Roles.Providers, …). Andererseits findet man aber auch genügend Stellen, an denen das zugunsten andere Datenstrukturen, etwa NameValueCollection oder Arrays, nicht passiert. Und auch CollectionBase (die man als “Schnittstellenklasse” bezeichnen könnte) delegiert die eigentliche Datenhaltung zwar weiter, ist aber so eng an ArrayList gekoppelt, dass an einen Austausch kaum zu denken ist.

Trotzdem versucht Microsoft das Konzept der Trennung weiter zu forcieren, zum Beispiel auch mit FxCop-Regeln für gegen Arrays und List<T>. Für wiederverwendbare Klassen, die relativ eigenständig entwickelt werden und in unterschiedlichen Kontexten eingesetzt werden sollen macht das durchaus Sinn.

Andererseits gilt wie so oft: “One size fits all” funktioniert nicht!
Zum einen macht es keinen Sinn, die konzeptionelle Trennung von Schnittstelle und Implementierung gleichmacherisch auf alles zu übertragen. Zum anderen wurden die Karten mit LINQ neu gemischt.

Wenn es nicht um wiederverwendbaren Code geht, sondern um Schnittstellen in meiner Anwendungsarchitektur, dann interessiert nicht die Abstraktion der Datenstruktur, sondern Effizienz und Features.

Je nach Architekturansatz und Gusto kommen dann oft LINQ-Interfaces (IEnumerable<T> oder IQueryable<T>) zum Einsatz, oder die tatsächlichen Container – Dank der Unterstützung von Enumerable.ToArray() und Enumerable.ToList() üblicherweise Arrays oder List<T>. Sobald man sich der Oberfläche nähert mag auch mal eine ObservableCollection<T> im Spiel sein.

ICollection und Konsorten spielen hier definitiv keine Rolle. Dagegen ist auch prinzipiell nichts zu sagen, solange man konsistent bleibt. Auch wenn FxCop sich beschwert. FxCop-Regeln kann man abschalten!

Fazit

Alles zusammengenommen – gewürzt mit veralteten Empfehlungen – ist das eine manchmal etwas unverdauliche Suppe, die wir da auslöffeln müssen.

Meine Empfehlung? Sich bewusst sein, dass es nicht die Antwort gibt, und dass unterschiedliche Kontexte unterschiedliche Lösungen brauchen. Bei wiederverwendbare Komponenten würde ich “konzeptioneller Reinheit” den Vorzug geben, in der Anwendungsentwicklung dem pragmatischen Ansatz.

 

Weitere Informationen und Diskussionen zum Thema:

  • “Collections (C# and Visual Basic)” (msdn)
  • “Selecting a Collection Class” (msdn)
  • “Why we don’t recommend using List<T> in public APIs” (Krzysztof Cwalina)
  • “FAQ: Why does DoNotExposeGenericLists recommend that I expose Collection<T> instead of List<T>?” (Code Analysis Team Blog)
  • stackoverflow: 1, 2, 3
Share |