Geschichten aus 1001 Plugins

Das ist die Geschichte von einem, der auszog abzuklären, wie man eine grosse konventionelle Applikation als moderne, interaktive Web-Applikation programmieren könnte, und der zwar nicht mit einer Antwort, aber doch mit einer Erleuchtung wieder nach Hause kam.

Wenn man sich Moneysoft ansieht, wird einem schnell klar, dass bei einer Realisierung als Web-Applikation ein rein Server-seitiger Ansatz mit statischem HTML ohne Einsatz von Javascript nicht genügt. Nur ein Beispiel hierzu: Man kann heute einen Anwender nicht mehr 20 Dinge eingeben lassen in einer Datenerfassungs-Maske und ihm erst nach dem Abschicken aller Daten sagen, dass alles falsch ist. Eine unzulässige Eingabe auf einem Textfeld erfordert eine sofortige Fehlermeldung, und das heisst im Browser Einsatz von Javascript in irgendeiner Form.

Ich habe darum abgeklärt, wie man heute denn so Web-Applikationen mit einem hohen Anteil an Logik im Client programmiert. Welche Javascript-Frameworks gibt es, die sich bewährt und Reife erlangt haben? Welche Programmier-Muster haben sich etabliert? Welche Regeln befolgen erfahrene Programmierer bei der Entscheidung, was Client-seitig und was Server-seitig implementiert werden soll?

Angetroffen habe ich einen Dschungel, wie ich ihn mir so nicht hätte träumen lassen: Buchstäblich Dutzende miteinander konkurrierender Javascript-Frameworks, Bibliotheken oder wie immer man das nennen mag. Sammlungen mit Hunderten von Plugins bei mindestens einem dieser Frameworks. Viele dieser Dinge mit mehreren Releases, die dazu noch oft in unglaublich schneller Folge erscheinen. Grosse verwirrende Tabellen, was in welchem Browser in welcher Version wie gut funktioniert – oder eben nicht. Und für Leute, die übermütig werden, weil sie meinen, sie hätten es geschafft, lange Abhandlungen darüber, was man alles anders machen muss, damit es auch mit Tablets und Smartphones gut klappt.

Blickt man auf jedes noch so kleine Problem, das sich beim Bauen von Web-Applikationen typischerweise stellt, wie z.B. ein schlauer Editor mit interaktiven Formatierungens-Funktionen als Aufsatz für Textboxen, entdeckt man nicht etwas, das sich als Standard etabliert hat, sondern einen wilden Haufen miteinander konkurrierender Lösungen verschiedenster Grösse und Qualität.

Ok, sagte ich mir, das ist wohl eben so, wenn sich etwas so stürmisch entwickelt wie das Internet, seine Standards und die Geräte, mit denen man auf Websites zugreift. Aber wie baut man da Software, die man bezahlen kann und die nicht nächstes Jahr schon völlig obsolet ist?

Ich kann mir ganz verschiedene Strategien vorstellen, wie man versuchen könnte, sich in diesem Dschungel sinnvoll zu bewegen und länger als ein paar Monate zu überleben. Man könnte die Client-Logik sorgfältig so wählen, dass mit möglichst wenig Javascript-Einsatz ein möglichst grosser Gewinn an Benutzerfreundlichkeit herausschaut: Weniger Javascript bedeutet weniger Abhängigkeiten und potentiell weniger Ärger.

Man könnte versuchen Wahrsager zu spielen und vorherzusehen, was sich in Zukunft einmal durchsetzen könnte, wenn sich die Situation dereinst einmal stabilisieren wird, und dann darauf wetten. Auf der einen Seite Pech, wenn man falsch wettet, aber aber der anderen Seite auch nicht sooo schwierig: jQuery wird auf jeden Fall unter den „Siegern“ sein, wenn Sie mich fragen.

Man könnte auch einen Satz von Open-Source-Komponenten zusammenstellen, der jetzt gut funktioniert, und diesen dann „adoptieren“, spricht selbst weiterentwickeln und an neue Browser und Standards anpassen – mindestens ein paar Jahre lang, bis man etwas Neues machen kann.

Ich hatte grosse Mühe, im Internet brauchbare Diskussionen darüber aufzutreiben, wie man die Strategie findet, die für die jeweils eigene Situation angebracht ist. Viele Leute scheinen noch nicht einmal die Notwendigkeit einer Strategie zu empfinden, und mixen frisch-fröhlich die neuesten Versionen von einem Dutzend oder mehr Plugins zu Web-Applikationen zusammen, als ob es kein Morgen gäbe.

Ich fühlte mich weit davon entfernt, eine Entscheidung darüber zu treffen, welchen Weg die Megos AG einschlagen müsste auf dem Weg zu einem Moneysoft.web, und war am Schluss ziemlich beunruhigt über die ganze Situation.

Aber dann dann kam sie, die eingangs angesprochene Erleuchtung, eines Abends kurz vor dem Einschlafen, und brachte zwar nicht die Antwort auf die Frage nach der Strategie, aber trotzdem ein Ende meiner Zweifel, ob das je etwas werden wird:

Frage: Wie ist es überhaupt möglich, dass es diese riesige Zahl an Javascript-Bibliotheken und -Plugins gibt? Antwort: Es muss einfach und nicht allzu zeitaufwendig sein, so etwas zu bauen. Und das wiederum heisst, dass es eine Obergrenze gibt, wie komplex und kompliziert diese Software überhaupt sein kann: nicht sehr.

Auf die eine oder andere Weise werden wir das darum in den Griff kriegen.

Zu guter Letzt noch ein Link: Ich habe im Zuge der beschriebenen Abklärungen gute Web-Applikationen gesucht, die von der Art der Funktionalität her mit Moneysoft vergleichbar sind (welche man breit gefasst als „Verwaltung administrativer Daten“ umschreiben könnte), und bin dabei auf smallinvoice gestossen. Funktioniert ausgezeichnet, sogar im relativ exotischen Opera-Browser, mit dem ich normalerweise unterwegs bin, was ein sehr gutes Zeichen punkto Einhaltung von Web-Standards darstellt, und wurde offenbar von einem vergleichsweise kleinen Team unter Schweizer Leitung gebaut. Geht doch!

Advertisements
Veröffentlicht in Keine Kategorie. Schlagwörter: , , . Leave a Comment »

IntelliSense und Erweiterungen von Klassen

IntelliSense in Visual Studio ist eine wunderbare Sache, die das Programmieren ungemein erleichtert. Eigentlich sollte heutzutage niemand mehr in einer Umgebung programmieren müssen, wo kein in etwa gleichwertiges Feature zur Verfügung steht. Trotzdem sahen wir ein ernstzunehmendes Problem damit, als wir hier in der Megos ernsthaft damit begannen, unsere neues Programmierwerkzeug Triton in C# zu implementieren.

IntelliSense scheint seine Listen immer stur alphabetisch zu sortieren und immer alles aufzulisten, ohne Filtermöglichkeiten. Das kann dan zu einem Problem werden, wenn man Klassen erweitert, die bereits eine Menge Members haben, und dann in der IntelliSense-Liste seine „eigenen“ Members (d.h. diejenigen der Erweiterung) kaum mehr findet. Je nach Art der Klassen benötigt man beim Implementieren bevorzugt eben diese eigenen Members, was das Ganze dann etwas mühsam macht.

Unsere Überlegungen zeigten uns, dass sich die Sache zuspitzt, wenn man Klassen für den Datenbank-Zugriff generiert, wo für jede Kolonne in einer Tabelle eine Property definiert wird, die sich dann zu all den Members der Zugriffs-Basisklasse gesellt und unter diesen irgendwie unterzugehen droht, obwohl sie doch zum eigentlichen „Witz“ der generierten Klasse gehört.

Man kann das bereits bei Visual-Studio-eigenen typed datasets beobachten: Eine Tabellen-Zugriffs-Klasse wird von System.Data.TypedTableBase abgeleitet, einer Klasse mit geschätzten etwa 100 Members. Eine Kolonne TitelKurs wird zu einer Property namens TitelKursColumn und wird von IntelliSense unter T eingeordnet; eine Kolonne WährungsKurs wird zu WährungsKursColumn und taucht dann in der Liste unter W und damit an einem ganz anderen Ort auf. Dieses Verhalten verunmöglicht es praktisch, sich per IntelliSense einen schnellen Überblick über alle Kolonnen zu verschaffen – aber wo ausser da soll denn dieser Überblick herkommen?

Es war schnell klar, dass es bei Visual Studio und IntelliSense, so wie jetzt implementiert, nur ein einziges „Rädchen“ gibt, an dem man überhaupt drehen kann, wenn man dieses Problem irgendwie lösen will: Will man Members zusammen sehen in einer IntelliSense-Liste, so müssen sie eben entsprechend heissen, d.h. alle mit irgendeinem Präfix beginnen.

Sie werden als geneigter Leser vielleicht schon ahnen, dass dieser Blog-Eintrag hier geradewegs auf ein Dilemma zumarschiert: Von Namenspräfixen wird in .NET und C# eigentlich abgeraten; verwendet man sie trotzdem, stecken einen gewisse Leute schnell einmal in die Schublade „Ewiggestrige“, die reserviert ist für Leute, die von ihren alten Gewohnheiten nicht lassen können und auch nicht verstanden haben, dass man heutzutage nur noch „natürliche“ Namen vergibt, weil man – eben gerade durch Features moderner IDEs wie z.B. IntelliSense – nicht mehr darauf angewiesen ist, vom Namen eines Dings irgendwelche Meta-Information ablesen zu können.

Aber wie gesagt, hier geht es nicht darum, sondern um eine Lösung für ein kleines, aber sehr lästiges Problem mit IntelliSense.

Wir sahen das Ganze als Wahl zwischen zwei Übeln: 1) einen Teil der Namen mit Hilfe von Präfixen verunstalten, aber damit den Nutzen von IntelliSense aufwerten, oder 2) den Empfehlungen und der Mehrheit der C#-Programmierer folgen, aber sich mit Situationen abfinden, in denen IntelliSense wenig hilft, obwohl es gerade da sehr nützlich wäre.

Nach einigem Hin und Her entschieden wir uns für das Übel 1). Wir wählten z.B. für die Properties unserer eigenen Klassen in Triton den Einbuchstaben-Präfix z, weil eine Abklärung ergab, dass nur wenige .NET-Klassen bereits Properties haben, mit mit Z beginnen, und damit diese Properties nicht nur zusammen angezeigt werden in einer IntelliSense-Liste, sondern auch noch herausstechen.

Seit dieser Entscheidung haben wir eine rechte Menge Code gemäss diesen Präfix-Konventionen erzeugt, und es ist eine erste Beurteilung des Erreichten möglich. Der gewünschte Effekt bei IntelliSense hat sich eingestellt: Man behält so tatsächlich ohne Probleme den Überblick über die eigenen Dinge im Gegensatz zu den „fremden“ Dingen des Frameworks. Aber hübsch sieht es irgendwie nicht aus, und eine richtige Gewöhnung an unsere mit Präfixen dekorierten Namen will sich eigentlich auch nicht einstellen.

Für jemanden, der sich im .NET-Framework wirklich gut auskennt, gäbe es vielleicht eine Wahlmöglichkeit 3), welche das Dilemma umgeht: ein Add-In programmieren, welches neben der IntelliSense-Liste eine zweite, entsprechend eingeschränkte Liste implementiert. Aber ganz soweit sind wir in der Megos noch nicht…

Veröffentlicht in Keine Kategorie. Schlagwörter: , . 1 Comment »

Mehrfachvererbung

Manchmal wird man ziemlich unverhofft mit einem Problem konfrontiert, das man schon lange kannte, aber von dem man nicht ernsthaft erwartete, ihm jemals zu begegnen. So ging es mir mit der Mehrfachvererbung.

Ohne mich je genauer damit zu beschäftigen, war ich bisher der Meinung, es sei schon in Ordnung, dass viele Programmiersprachen Mehrfachvererbung nicht unterstützen, denn auf der einen Seite waren mir mögliche und vor allem sinnvolle Anwendungen nicht klar, aber auf der anderen Seite möglicher Ärger wie z.B. schwer verständliche Programme sehr wohl.

Umso mehr überrascht es mich, dass ich mir beim Design unseres neuen .NET-basierten Programmierwerkzeugs Triton jetzt genau diese Mehrfachvererbung wünsche, sie aber natürlich in C# nicht bekomme!

Worum geht es? Ich möchte die Funktionalität von Controls für Forms erweitern, notabene die von Standard-Controls wie TextBox, CheckBox, Button usw. Ich brauche z.B. Unterstützung für eine „schlaue“ Validierung von Eingabewerten, wo ich zwischen „validiert in Bezug auf den aktuellen Wert des Controls selbst“ und „validiert auch unter Berücksichtigung gegenseitiger Abhängigkeiten“ unterscheiden möchte.

So entsteht der Bedarf, eine neue Angabe ValidationState bei den Controls unterzubringen, am liebsten gleich zusammen mit einigen Methoden, welche das Validieren unterstützen.

Natürlich steht es mir frei, von allen schätzungsweise etwa 10 System.Windows.Forms.Control-Klassen, die ich brauche, neue Klassen abzuleiten und bei allen diesen eine Property ValidationState einzuführen, aber so erhalte ich natürlich 10 verschiedene Klassen mit 10 völlig unabhängigen und inkompatiblen Properties.

Ideal wäre natürlich, die Basisklasse Control selbst um eine Property ValidationState plus zugehörigen Code erweitern zu können, aber zumindest mit C# 3.0 wäre der einzige Weg hierzu eine Modifikation des Framework-Source-Codes und eine Neukompilation, was für mich natürlich nicht in Frage kommt. Auch eine abgeschwächte Variante, bei der ich Control unverändert lasse, aber eine eigene Klasse SmartValidationControl oder so quasi in den Baum der Vererbung „einfügen“ darf, hat dieselben nicht erfüllbaren technischen Voraussetzungen.

Und hier kommt jetzt die Mehrfachvererbung ins Spiel: 10 von diversen Controls abgeleitete Klassen wären in Ordnung, wenn sie ausser vom jeweiligen Control auch noch von einer zweiten Klasse SmartValidationControl ableiten dürften!

Was wäre mit 10 UserControl-Klassen mit einer gemeinsamen Basisklasse und mit dem jeweiligen eigentlichen Control als Kind? Dieser Ansatz ist natürlich möglich, artet aber aus in eine umfangreiche Fleissaufgabe, eine Menge Properties der Controls „durchzuschlaufen“, damit sie im Designer als Properties des Containers für Änderungen zur Verfügung stehen.

Schlussendlich bin ich beim folgendem Ansatz gelandet, den ich als das „geringste Übel“ ansehe: Ich leite 10 Klassen von 10 verschiedenen Controls ab, gebe aber allen diesen Klassen ein bestimmtes Interface, das ich dann eben 10 Mal implementieren muss.

Bei meinen Abklärungen über Mehrfachvererbung per Google bin ich über ein paar Seiten gestolpert, die sich vielleicht lohnen weiterzugeben:

Hier erläutert jemand aus dem C#-Team von Microsoft, dass die CLR selbst offenbar einen Weg bietet für Mehrfachvererbung, damit zumindest im Prinzip die Möglichkeit besteht, .NET-basierte Compiler zu bauen für Sprachen, welche Mehrfachvererbung umfassen.

hier hat jemand Mehrfachvererbung in C# so sehr vermisst, dass er sich eine „Simulation“ derselben ausgedacht hat, die recht trickreich mit Operatoren für implizite Typumwandlungen arbeitet. (Ich finde das Resultat insgesamt gesehen trotzdem ernüchternd.)

Und hier findet man schliesslich ein schon etwas älteres Interview mit dem „C# Compiler Program Manager“ bei Microsoft, dem man die offizielle Haltung von Microsoft zum Thema entnehmen kann.

Anhand der vielen Treffer, die Anfragen nach multiple inheritance oder auch spezifisch c# multiple inheritance in Google produzieren, kann man sehen, dass es sich offenbar um eine Sache handelt, die immer wieder aufkommt. Es wäre interessant zu wissen, ob es keine elegante Lösung des Problems geben kann, weil das Universum eben ist wie es ist, oder ob einfach noch niemand die geniale Idee gehabt hat…

Veröffentlicht in Keine Kategorie. Schlagwörter: , , . 4 Comments »

Die Geschichte vom unscharfen Text

Windows Presentation Foundation, kurz WPF, ist eine relativ neue Technologie von Microsoft, um für .NET-Programme grafisch anspruchsvolle Benutzeroberflächen zu bauen. Ein wie ich finde sehr gelungenes Beispiel einer mit Hilfe von WPF erstellten kommerziellen Applikation (also etwas in der Art, wie die Megos auch Software anbietet), findet man hier.

Es gibt bei WPF allerdings ein Problem, und je nach dem, wen man fragt, sogar ein ziemlich gewichtiges: WPF verwendet für sämtliche Textausgaben Anti-Aliasing, mit dem Resultat, dass Text mehr oder weniger unscharf wird, je nach Monitor, Bildschirmauflösung, Schrift und dem Sehvermögen des Betrachters. Ich habe hier zwei WPF-Buttons mit ihren Beschriftungen in fast unfairer Weise vergrössert, damit man das Phänomen in seiner ganzen Pracht sieht (in Originalgrösse sehen die Buttons brauchbar aus):

WPF Anti-Aliasing

Ein weiteres Beispiel findet man hier.

Anti-Aliasing bei Textausgabe muss nicht schlecht sein, und schon seit einiger Zeit leistet die ClearType-Fonttechnologie auf Windows XP z.B. auf gewissen Notebook-Displays gute Dienste. Aber: Man kann es bei WPF nicht ausschalten, auch in der neuesten Framework-Version 3.5 nicht, und es ist eine von ClearType unabhängige, unterschiedliche Implementation, die offenbar nicht immer gleich gut ist.

Wie man dieser Diskussion in einem MSDN-Forum entnehmen kann, bitten gewisse Entwickler Microsoft nun schon seit über 2 Jahren inständig darum, man möge doch einen Schalter einführen, um die Sache abzuschalten. Passiert ist offenbar in der ganzen Zeit – ausser einigen Erklärungsversuchen von Microsoft und Zusicherungen, man nähme das Problem ernst – nichts.

Es handelt sich um eine Sache, die vielschichtiger ist, als man nach dem ersten Blick meint. Die in der WPF verwendete Technologie ermöglicht es, Buchstaben quasi genauer als nur auf Pixel genau zu positionieren, und das kann wichtig sein bei dynamischen Layout- und Grössenänderungen, wie sie WPF unterstützen möchte.

Man kann auch relativ schnell mit einem Argument von Microsoft einig gehen, dass Anti-Aliasing auf Monitoren mit hoher Pixeldichte (Anzahl Pixel pro Distanz), also z.B. nicht mit den üblichen 96 Pixels pro Inch, sondern 200 oder noch mehr, wunderbar aussieht.

Man könnte sich trotzdem relativ einfach auf den Standpunkt stellen, dass etwaige „Nebenwirkungen“ des Abschaltens des Anti-Aliasing voll auf den Schultern des Programmierers lasten, welcher abschaltet, und ich denke, die Leute in der erwähnten Diskussion wären damit auch sofort einverstanden. Trotzdem hatte Microsoft bisher kein Einsehen.

Solche Geschichten faszinieren mich oft, weil ich mich unweigerlich frage, was wohl jeweils die Geschichte hinter der Geschichte ist. Ich spekuliere gerne über die „Wahrheit“, die oft ziemlich wenig mit Technik und ziemlich viel mit Psychologie zu tun haben dürfte. Es muss fast mehr dran sein als einfach nur ein „Informatik-Problem“, sonst wäre die Sache schon längst ausgestanden.

Darf ich also mal ein bisschen spekulieren, und ein paar Verschwörungstheorien über den nach wie vor unscharfen WPF-Text in die Welt setzen? (Und es sind Spekulationen, ich weiss nicht mehr als Sie!)

  • Irgend ein hohes Tier bei Microsoft ist Fan von Anti-Aliasing, will von Kritik einfach nichts wissen und ist so mächtig, dass er oder sie nicht überstimmt werden kann.
  • Microsoft möchte Druck ausüben auf die Hersteller von LCD-Panels, damit diese tatsächlich dazu übergehen, in Richtung hoher Pixeldichten zu entwickeln, was sie im Moment eher nicht tun – die Displays werden meistens einfach nur grösser.
  • Irgend jemand bei Microsoft mit viel Einfluss und Reputation hat sich am Anfang dermassen stark gemacht für Anti-Aliasing, dass er oder sie jetzt unmöglich eine Fehleinschätzung zugeben kann.
  • Das ungeliebte Anti-Aliasing bleibt drin sozusagen als Bestrafung für jemanden, der es zu verantworten hat. (Sobald der oder die „weggemobbt“ ist, kommt der geforderte Aus-Schalter.)
  • Microsoft spekuliert, auf die Entwickler Druck ausüben zu können, wenn man WPF-Applikationen sofort als solche erkennt, unter anderem eben am Anti-Aliasing, so in der Art von „Was, Du arbeitest noch mit Windows Forms?“
  • Wie dem auch sei, ein glückliches Ende der Geschichte vom unscharfen Text ist im Moment offenbar nicht in Sicht…

    Veröffentlicht in Keine Kategorie. Schlagwörter: , . 1 Comment »

    Technologie-Inflation

    Ein Artikel in der Zeitschrift iX hat mich heute darauf aufmerksam gemacht, dass zusammen mit dem Service Pack 1 für das .NET Framework 3.5 nun nach langem Warten die erste definitive Version des sogenannten ADO.Net Entity Framework zur Verfügung steht.

    Es wurde schon eine ganze Menge darüber geschrieben, was es mit diesen „Entities“ auf sich hat. Z.B. ist die entsprechende Wikipedia-Seite ein guter Startpunkt, um sich einzulesen. Ich will deshalb nicht noch mehr Technisches darüber schreiben, sondern die Gelegenheit ergreifen, um ein bisschen über die Sache zu „philosophieren“.

    Applikationen für vorwiegend administrative Zwecke, wie sie die Megos anbietet, sind sehr stark geprägt durch den Zugriff auf die Daten. Seit wir vor einiger Zeit beschlossen hatten, für die Programm-Entwicklung auf .NET umzusatteln, verfolgte ich deshalb ziemlich aufmerksam, was sich bei .NET in Sachen Datenzugriff und Datenverwaltung tut, und wurde schnell neugierig, als ich vor einiger Zeit zum ersten Mal von diesem Entity Framework hörte.

    Was ich sah, als ich mich näher damit beschäftigte, hat mir zunächst fast die Sprache verschlagen: So ein Riesen-Ding, mit eigener SQL-Variante für die Abfrage, mit eigener Art von Datenbank-Modell, das über das relationale Modell hinausgeht, samt zugehörigem, nicht zu klein geratenem Modellierungs-Tool, plus jeder Menge neuer .NET-Klassen natürlich. Und fast noch bemerkenswerter als die Grösse der ganzen Geschichte kam mir deren Komplexität vor.

    Dann wurde mir klar, dass .NET mit LINQ-to-SQL und dem Entity Framework gleich zwei Technologien enthalten wird, welche sich bezüglich der grundlegenden Aufgabe des sogenannten OR-Mapping überschneiden und konkurrenzieren. Die mögliche Antwort von Microsoft wird vielleicht – nicht unbedingt überraschend – noch mehr Neues, noch mehr Grosses und Komplexes sein, in Form von LINQ-to-Entities.

    Ich habe mich unweigerlich gefragt, wie viele Leute wohl auf der Welt eine Datenbank bewirtschaften müssen mit einer Struktur, die so vielfältig und komplex ist, dass man dieses Entity Framework zum Einsatz bringen kann und netto etwas herausschaut dabei, will sagen: Der Gewinn an Funktionalität und Flexibilität beim Umgang mit der Datenbank in den .NET-Programmen wiegt die Arbeit auf, die man aufwenden muss, um sich in diese riesige Geschichte einzuarbeiten, und wiegt dazu noch den Ärger auf, den man hat durch Bugs, die es fast unweigerlich geben muss in so viel neuem Code.

    Und die Frage „Soll ich auf das Entity Framework setzen?“ hat natürlich noch ganz andere Seiten. Soll ich meine Applikation um eine Technologie herum bauen, die ziemlich Microsoft-spezifisch ist? Wie langlebig wird diese Sache sein? Die Liste der Datenbank-Zugriffs-Technologien, die Microsoft zu „Legacy“ heruntergestuft hat, enthält schon einige Einträge (ODBC, DAO, OLE DB), und vielleicht kommt ja schon in relativ kurzer Zeit ein Eintrag dazu, wenn Microsoft sich eingestehen müsste, dass zwei OR Mappers einer zuviel ist.

    Interessanterweise ist es mir bei einer Google-Suche als Vorbereitung auf das Schreiben dieses Blog-Eintrags nicht gelungen, Leute zu finden, die sich wie ich angesichts der Grösse, der Komplexität und des proprietären Anstrichs des Entity Framework Sorgen machen und erst einmal abwarten, bevor sie es einsetzen. Aber vielleicht ist es dafür einfach noch etwas zu früh…

    Veröffentlicht in Keine Kategorie. Schlagwörter: , . Leave a Comment »

    ReadOnlyCollection

    Jeder, der eine halbwegs umfangreiche Klassen-Sammlung in C# designen muss, hat gute Chancen, auf folgende grundlegende Design-Frage zu stossen: Eine Klasse soll eine List enthalten, die zwar gegen aussen sichtbar ist, die man aber nicht direkt verändern darf – sämtliche Änderungen sollen quasi indirekt mit Hilfe von Methoden der Klasse erfolgen. Für eine solche Anforderung kann es viele denkbare Gründe geben; schon nur, wenn man die Anzahl Änderungen an der List zählen möchte, sollte es besser nicht möglich sein, dass sich jemand an der Zählung vorbeimogelt, indem er sich die Liste geben lässt und sie dann selbst verändert.

    Ein kleines synthetisches Codebeispiel hierzu:

    namespace ReadOnly {
      class Container {
    
        private List<int> numbers;
        public List<int> Numbers {
          get { return numbers; }
        }
    
        public void AddNumber(int n) {
          numbers.Add(n);
        }
    
        public Container() {
          numbers = new List<int>();
        }
      }
    
      class Program {
        static void Main(string[] args) {
          Container c=new Container();
          c.AddNumber(5);     // soll nur so funktionieren
          c.Numbers.Add(5);   // soll verboten sein
        }
      }
    }
    

    Mein erster Gedanke war, dass es in C# vielleicht ein Äquivalent zu C++ const gibt und man damit etwas machen kann. Eine Abklärung ergab, dass die CLR zwar eine gewisse Unterstützung bietet in dieser Richtung (für Managed C++), diese aber in C# nicht zur Verfügung steht.

    Dann stiess ich auf die Property IsReadOnly, welche im Interface IList enthalten ist. Das sieht zwar auf den ersten Blick hoffnungsvoll aus, aber die Anwesenheit dieser Property im Interface heisst noch lange nicht, dass man im Falle einer „templated class“ etwas damit machen kann. Ich habe auf jeden Fall keinen Weg gefunden, im konkreten Falle einer List<int> deren Property IsReadOnly irgendwie zu überdefinieren, und selbst wenn dies gelänge, würden sich wohl Methoden wie Add der Template-basierten Klasse überhaupt nicht dafür interessieren.

    Schliesslich förderte meine Suche die Klasse ReadOnlyCollection zu Tage, welche man wie folgt auf das Problem ansetzen kann:

    namespace ReadOnly {
      class Container {
    
        private List<int> numbers;
        public ReadOnlyCollection<int> Numbers {
          get { return numbers.AsReadOnly(); }
        }
    
        public void AddNumber(int n) {
          numbers.Add(n);
        }
    
        public Container() {
          numbers = new List<int>();
        }
      }
    
      class Program {
        static void Main(string[] args) {
          Container c = new Container();
          c.AddNumber(5);     // funktioniert nur so
          c.Numbers.Add(5);   // compiliert nicht, 'ReadOnlyCollection.Add' gibt es nicht
        }
      }
    }
    

    Etwas unbefriedigend an dieser Lösung ist, dass mit Hilfe der Methode AsReadOnly ein neues Objekt erzeugt werden muss.

    In irgendeinem Forum habe ich dann folgende Lösungs-Variante gefunden, welche ohne ein neues Objekt auskommt:

    namespace ReadOnly {
      class Container {
    
        private List<int> numbers;
        public IEnumerable<int> Numbers {
          get { return numbers; }
        }
    
        public void AddNumber(int n) {
          numbers.Add(n);
        }
    
        public Container() {
          numbers = new List<int>();
        }
      }
    
      class Program {
        static void Main(string[] args) {
          Container c = new Container();
          c.AddNumber(5);     // funktioniert nur so
          c.Numbers.Add(5);   // compiliert nicht, 'IEnumerable.Add' gibt es nicht
        }
      }
    }
    

    Eine List<int> implementiert natürlich selbst bereits das Interface IEnumerable, so dass die Sache rein zur Compilierzeit stattfindet und die Property Number technisch gesehen gleich die Liste selbst zurückgibt. Unschön ist allerdings, dass man mit einem IEnumerable-Objekt nichts weiter machen kann als per foreach die Elemente durchgehen; noch nicht einmal die Anzahl Elemente kann man direkt abfragen.

    Nach einigem Abwägen habe ich beschlossen, für die Megos-eigene Klassen-Bibliothek Triton, die gerade entsteht, das Problem zu ignorieren und keine technische Vorkehrungen zu treffen, um mit Hilfe einer der geschilderten Methoden Veränderungen an solchen Listen zu verhindern. Wir sind wenige, erfahrene, disziplinierte Programmierer, die keine Mühe haben mit dem Befolgen von Konventionen wie „Verändere keine Listen-Properties direkt“.

    Natürlich sähe das anders aus, wenn man z.B. eine kommerziell vertriebene Klassen-Bibliothek für den Gebrauch durch viele andere Programmierer bauen müsste. Aber auch da gäbe es vielleicht die Möglichkeit, die direkten Veränderungen selbst nicht zu verunmöglichen, sie aber dennoch zu entdecken und mit einer Exception zu beantworten, indem man einerseits die Anzahl Aufrufe von AddNumber zählt und andererseits an „strategischen“ Orten im Code die Anzahl Elemente der Liste gegen diesen Zähler prüft.

    Veröffentlicht in Keine Kategorie. Schlagwörter: , . Leave a Comment »

    Mehrfachvererbung

    Vor einigen Wochen stand ich recht unerwartet vor einem trickreichen Design-Problem, bei dem es sich lohnen düfte, hier davon zu erzählen.

    Für unsere im Entstehen begriffene neue .NET-basierte Programmierumgebung Triton wollte ich eine neue Control-Klasse definieren. Es ging darum, die Fokus-Steuerung, die Validierung und das Melden von Fehlern gegenüber der Standard-Klasse Form zu verbessern und zu generalisieren, und das bedeutete auch gewisse Erweiterungen bei der Funktionalität der Controls.

    Also, an die Arbeit, und eine Basis-Klasse TritonControl definieren, welche die nötigen grundsätzlichen Erweiterungen und die Zusammenarbeit mit TritonForm enthält, und dann TritonTextBox, TritonCheckBox usw. davon ableiten…

    Aber Moment mal: Wie soll das überhaupt gehen? Man kann der bestehenden Klasse System.Windows.Forms.TextBox ja keine neue Basis-Klasse TritonControl „unterjubeln“ bzw. sich in die Klassenhierarchie irgendwo zwischen Control und TextBox hineinzwängen. Auf der anderen Seite, gegen „oben“ in der Hierarchie, ist es zwar einfach, von TextBox eine TritonTextBox abzuleiten, aber so ergibt sich natürlich auch keine gemeinsame Basis-Klasse, sondern beim Ableiten von einem Dutzend .NET-Control-Klassen nur ein Dutzend typenmässig inkompatibler neuer Klassen, mit denen sich kein vernünftiges System bauen lässt.

    Es gibt meiner Meinung nach nicht viel, was C++ der Sprache C# voraus hat, aber immerhin: In C++ wäre man jetzt hingegangen und hätte locker per Mehrfachvererbung die neue Klasse TritonTextBox eben von TextBox und TritonControl abgeleitet. Das ist so in C# nicht möglich.

    Eine Analyse des Problems zeigte zwei mögliche Lösungen:

    Erstens könnte man TritonControl von UserControl ableiten, und TritonTextBox wiederum von TritonControl. Ein solches Control würde dadurch zu einer Eingabemöglichkeit für einen Text, indem es zur Laufzeit dynamisch ein Child Control für sich vom richtigen Typ erzeugt, konkret eine System.Windows.Forms.TextBox, oder indem man im Designer statisch dem UserControl ein solches Child Control gibt.

    Zweitens könnte man TritonTextBox von TextBox ableiten, aber zusätzlich mit einem Interface ITritonControl ausstatten.

    Beim ersten Ansatz ist hauptsächlich unschön, dass man eine Menge Properties definieren muss in den von TritonControl abgeleiteten Klassen, damit deren Werte an die „inneren“, quasi an die echten Controls, weitergegeben werden können.

    Beim zweiten Ansatz ist unschön, dass man das Interface mit einer ganzen Reihe von Methoden und Properties bei jedem abgeleiteten Control separat implementieren muss.

    Nach einigen Überlegungen entschieden wir uns für den zweiten Ansatz. Das Implementieren des Interface ist zwar eine gewisse Fleissarbeit, aber dafür hat man sicher keinen Ärger mit dem Designer, für den eine TritonTextBox immer noch eine waschechte TextBox ist, mit der richtigen visuellen Darstellung, dem richtigen Design-Verhalten, und allen interaktiv spezifizierbaren Eigenschaften, für welche man die .NET-Controls so mag.

    Veröffentlicht in Keine Kategorie. Schlagwörter: . Leave a Comment »