Archive for 2008

Data Source Independent DAL

Dienstag, März 11th, 2008

Another short piece of personal learning. Ich markiere für einmal den grossen Architekten. :)

Die Idee eines Data Access Layers ist gemeinhin, Datenzugriffe datenbank- oder sogar datenquellenneutral (neben relationalen Datenbanken allein können ja auch Textdateien oder ein Web Service als Datenquelle dienen) zu halten. In der Praxis ist dies nach meinen Erfahrungen nicht immer genau so der Fall, wie dies die Theorie anpreist.

Die Theorie sagt: Der Presentation Layer präsentiert Daten und enthält keine Logik (höchstens formelle Prüfung oder Plausibilisierung von Eingaben), der Business Layer hantiert mit den Business-Objekten und implementiert die Logik, der Data-Access Layer liest und speichert die Daten und abstrahiert die Zugriffe auf die Datenquelle auf allgemeinem Level.

Ich wollte nun einen Business Layer, der weder von der Datenquelle abhängt noch hunderte Zeilen Code enthält, um die netten Rückgabewerte und Ausgabeparameter wieder in Objekte umzubauen. Ich wollte im DAL auch keine Strukturen definieren, dessen Felder denjenigen im Business-Objekt entsprechen. Ein Objekt (Business Entity!) soll "as it is" ohne weitere Bearbeitung zur Speicherung gereicht werden und auch fixfertig wieder aus dem DAL kommen.

Dafür habe ich nun ein separates Assembly gebaut mit abstrakten Basisklassen für die Business-Objekte. Business Layer und DAL haben beide eine Referenz darauf, sodass beide die Grundstruktur der Objekte kennen. Hier eine schnelle PowerPoint-Skizze:

Architekturskizze

Der Business Layer kann nun dem DAL beliebige Instanzen von Klassen übergeben, welche von den (abstrakten) Basisklassen im DAL abgeleitet sind. Im Business Layer kann ich meine Business-Entitäten erstellen, die von den Basisklassen erben, meine Methoden erstellen und zusätzliche Interfaces implementieren, beispielsweise für bequemes .NET Windows Forms Data Binding.

Zur Implementierung habe ich vorerst nur die gekapselten Felder und das IEquatable Generic Interface in der Basisklasse implementiert: Die Entität soll grundsätzlich sofort einsetzbar sein (für Business-Layer und DAL!), aber keine besonderen Businessfunktionalitäten bereitstellen. Die braucht der DAL nämlich nicht, und hat sie auch nicht zu brauchen.

Nein, allzu neu ist die Idee nicht. Bei simple talk ist die Idee im Artikel ".NET Application Architecture: the Data Access Layer" (der Artikel ist sehr empfehlenswerte Lektüre!) beispielsweise aufgegriffen, diskutiert und Alternativen gegenübergestellt. Sie beschreibt diesen Approach als akademisch:

From an academic standpoint, this approach is probably the truest form of a data abstraction for a DAL because you can make the shared classes completely data-source independent and not just database independent.

Diesen Eindruck macht er auch auf mich. Ich bin mir nicht sicher, inwiefern er bei grossen Projekten mit aberhunderten von Entitäten wirklich bequem durchführbar ist. Aber er ist bestimmt nicht schlecht; ich werde damit experimentieren.

Stored Procedures

Dienstag, Februar 26th, 2008

Die Diskussion in der Schulklasse um Stored Procedures ist erneut aufgekommen: Im Rahmen unserer so-richtig-Vier-Tier-Hangman-Applikation, die wir für die Schule entwickeln müssen, wurde deren Notwendigkeit in Frage gestellt und diskutiert. Ich bin bekanntlich immernoch ein Verfechter von Stored Procedures für jeden kleinen SQL-Befehl, der gegen die Datenbank abgesetzt wird.

Grund 1: Stored Procedures sind eine definierte Schnittstelle

Stored Procedures definieren zwischen Datenbank und jeder Applikation eine klare Schnittstelle. Mit anderen Worten:

Stored procedures are a contract. (...) The header of the stored procedure defines the parameters that the developer must supply, and the body is where the DBA puts all of their voodoo magic to get the data you requested.

Die treffende Beschreibung stammt aus dem Post Service Oriented Databases auf PaulStovell.NET.

Durch die Stored Procedure wird es leichter, die Datenbank zu erweitern, die Daten weiter zu normalisieren, total anders abzulegen oder Felder umzubenennen. Ausserdem können Optimierungen in der Abfrage vorgenommen werden, ohne an der Applikation selbst zu schrauben.

Trotzdem ist es natürlich gefährlich, beliebige Änderungen beispielsweise an Feldnamen vorzunehmen und dann durch die Stored Procedure unter dem alten Namen anzuzeigen, wenn dadurch die Einheitlichkeit der Namen (und somit der Überblick über das Gebilde) verloren geht.

Grund 2: Stored Procedures sind vorkompiliert

Stored Procedures sind vorkompiliert. Somit wird die Abfrage nicht bei jeder Verwendung neu interpretiert weil wieder von der Applikation versandt (zumindest beim Microsoft SQL Server - ich kenne nicht jede DB). Dazu sei ein Artikel SQL Server Stored Procedures von About Databases Guide Site zitiert:

Precompiled execution. SQL Server compiles each stored procedure once and then reutilizes the execution plan. This results in tremendous performance boosts when stored procedures are called repeatedly.

Natürlich macht sich das erst ab einer bestimmten Nutzungsfrequenz und/oder Query-Komplexität bezahlt, aber es schadet auch sicher nicht. :)

Grund 3: Netzwerk-Traffic

Je länger das Query, desto mehr Netzwerkverkehr verursacht die Übermittlung. Ein Stored Procedure Aufruf ist je nach länge wesentlich (oder auch unwesentlich) kürzer.

Grund 4: Mehr Sicherheit durch restriktivere Permissions

Werden Stored Procedures konsequent verwendet, braucht erhält ein Web- oder Service-User, respektive der Benutzer selbst, keine direkten Zugriffsrechte auf Tabellen. Ihm wird lediglich eingeräumt, die Stored Procedures auszuführen, die er benötigt. Der Entwickler oder DBA legt auf diese Weise genau die Queries fest, welche der Benutzer auszuführen hat. Alles andere geht nicht.

Nachtrag: Heute, am 5. Mai, bin ich zu diesem Thema auf simple-talk über "Bad Database Security" von Tony Davis gestossen.

Grund 5: Änderungen an Queries (bei Client-Applikationen)

Bei Applikationen, die auf dem Client laufen und nicht auf dem Server, werden hart codierte Queries mit auf den Client kopiert. In einer neuen Version ändert sich eine Abfrage und ein Benutzer holt sich die neue Version nicht. Es gibt zwei blöde Szenarien:

  1. Blöd: Das Query in der alten Version funktioniert nicht mehr und der Benutzer kann nicht arbeiten. Dies geht in Grund 1 hinein, aber kann natürlich auch mit Stored Procedures passieren, falls sich eine Schnittstelle ändern muss.
  2. Blöder: Das Query liefert Daten, die es nicht liefern sollte. Nehmen wir an, in die Datenbank wird ein neues Feld "IsUserVisible" (Bit) eingefügt. Neu werden den Benutzern nur noch die Einträge angezeigt, welche "IsUserVisible" auf 1/true gesetzt haben. Krasser Häcker Hans-Detlev startet die alte Version und sieht Informationen, die er vielleicht besser nicht sehen sollte.

Was kein Grund ist...

Kein Grund ist meiner Meinung nach das SQL-Injection-Problem. Zwar kann die Tragweite dank eingeschränkten Rechten kleiner sein, aber folgendes kann der geneigte Bastler immer noch machen:

string sql = "EXEC MyStoredProc @Filter = \'" + filter + "\'"

Umgekehrt geht auch folgendes:

string sql = "SELECT * FROM Hubschrauber WHERE HubschrauberId = %1";
// ... und hier mit einem DbCommand-Objekt und Parametern arbeiten

Hm...

Was gibt es dazu für andere Meinungen, Alternativen? Oder wie sieht das auf den verschiedenen DBs aus?

InfoPath, Expressions and 256 Characters

Dienstag, Februar 12th, 2008

For once I'm writing in English, because I am translating English developer slang to German very badly (even worse that I write in English :P) and I'm sure there are more English-speaking developers. Maybe I will write a German version later on.

InfoPath behaves pretty strange when I use expressions that are longer than 256 characters. This morning I worked with rules and conditions on click of a button on an InfoPath form. In my opinion the following is a bug, but it might be a feature too of course:

InfoPath Button Properties Window

If you replace "(long expression here)" with any kind of expression which is longer than 256 characters, everything will go well when you press OK. Now open the properties window again. The expression will be cut to 265 characters. You can paste it again and it will be well again.

The problem is, e.g. you change a condition for a rule that applies on click. Everything will look well, but Apply or OK will not work. As soon as you close the dialog, the changes will be wasted. As a workaround (in German: "Würgaround"), change the expression to "asdf" (or anything that is shorter than the magic 256 characters), make your changes, apply the changes, reopen the window and paste the expression again.

The Tumble Dryer

Donnerstag, Januar 10th, 2008

Ich ziele nicht auf die Lyrics von "Retirement", Kaiser Chiefs, nein.

"Ich selber habe die Erfahrung gemacht, daß normale Shirts, Hosen, usw., die nicht gerade besondere Applikation und Sonderstoffe beinhalten, auch getrocknet werden können." (Tobias Haase in de.etc.haushalt)

Dies las ich die in de.etc.haushalt, gefunden über Google. Die Erfahrung kann ich bestätigen, übernehme aber selbstverständlich keinerlei Haftung. ;)

Mein Problem ist, dass der Trockenraum des Wohnblocks schlecht ist. In zweierleit Hinsicht:

  • Die Raumluft wird weder geheizt noch getrocknet und die Wäsche trocknet entsprechend langsam.
  • Es stinkt zwischendurch ein wenig faulig (oder so ähnlich, woher auch immer das kommt) oder nach Zigarettenrauch aus dem Treppenhaus oder dem Lift. Wenn ich die Wäsche nun drei Tage hängen lassen muss, nimmt sie eine Mischung aus sämtlichen Gerüchen auf.

Nun habe ich Gebrauch vom Tumbler gemacht, obwohl die meiste Wäsche dafür nicht offiziell geeignet gewesen wäre. Quer durch, von Shorts bis Pullover, alles in eine Ladung und auf dem Schonprogramm durch. Kein Problem, lediglich nicht ganz "schranktrocken". Aber diese Restfeuchtigkeit liess sich gut in einigen Stunden in der Wohnung wegtrocknen.

Warum ich das schreibe? Ich habe lange gegoogelt, um eine Empfehlung bezüglich Tumlerbenutzung bei normalen Textilien zu finden. Massenhaft Werbung für Geräte habe ich gefunden, und in der Wikipedia historische Fakten. Kurz vor der Kapitulation stiess ich auf den oben genannten Beitrag. Und selbstverständlich beweist man ja auch Hausmännlichkeit.