Popularität des Microsoft Ribbon controls

August 18th, 2008

Hallo,

die aktuell in Entwicklung befindliche Software meines Unternehmens EmPowerTec verwendet das Microsoft Ribbon zur Steuerung der Anwendung. Während ich persönlich von der höheren Produktivität (und auch der optischen Attraktivität – “eye candy”) schon immer überzeugt war, gab es Anfangs doch viel Skepsis ob das Ribbon der richtige Ansatz ist. Teilweise bezog sich diese Kritik auch auf Microsoft’s Vorgehen, ein bereits vorhandenes GUI (in den Microsoft Office Anwendungen) zu ersetzen und auf den Versuch die Ideen als “intellectual property” zu patentieren um potentielle Wettbewerber zu behindern.

Inzwischen ist mein Eindruck dass für Neuentwicklungen das Ribbon-Konzept zum Standard geworden ist und eine breite Akzeptanz gefunden hat. Als Beispiel kann man sich diese Diskussion in dem Business Of Software forum auf joelonsoftware.com anschauen.

Hier gibt es weitere Beispiele für Anwendungen mit Ribbon controls.

Und hier noch ein Beispiel aus der erwähnten Anwendung:

Example for Ribbon control

Den eigentlichen Witz des Ribbons kann man so nicht ohne weiteres erkennen: je nach Kontext wird das passende “ribbon tab” automatisch aktiviert und macht so genau die relevante Funktionalität verfügbar.

Im obigen Beispiel wurde in ein editor window geklickt woraufhin das “Edit”-tab des Ribbons aktiviert wurde. Würde man in das treeview “Project files” im linken Bereich klicken, würde automatisch das “Project”-tab aktiviert werden.

Viele Grüße,
Andreas

Technorati Tags:

Erstellung von Parsern in C++ mit der boost::spirit library (Teil 2)

August 15th, 2008

Hallo,

nachdem ich im letzten Posting zu diesem Thema einige grundlegende Überlegungen zum Einsatz der boost::spirit C++ parser library beschrieben habe möchte ich heute den konkreten Einsatz in dem bereits beschriebenen Beispiel zeigen.

Für den beschriebenen Ansatz werden folgende Include-Direktiven benötigt:

//lint -save -elib(*)
#include <boost/spirit/core.hpp>
#include <boost/spirit/tree/tree_to_xml.hpp>
#include <boost/spirit/tree/parse_tree.hpp>
//lint -restore

Die spirit header files sind nicht “PC-Lint clean”, weshalb entsprechende warnings unterdrückt werden sollten. Da boost::spirit eine “header only” library ist, sind keine weiteren Eingabedaten für den linker erforderlich.

Hier sind einige typedefs, die die Nutzung der boost-Klassen erleichtern. Ich habe sie in einem “anonymous namespace” innerhalb des entsprechenden cpp-files definiert:

typedef char const*         iterator_t;
typedef tree_match<iterator_t> parse_tree_match_t;
typedef parse_tree_match_t::const_tree_iterator iter_t;
 
typedef pt_match_policy<iterator_t> match_policy_t;
typedef scanner_policies<skip_parser_iteration_policy<space_parser>, match_policy_t, action_policy> scanner_policy_t;
typedef scanner<iterator_t, scanner_policy_t> scanner_t;
typedef rule<scanner_t> rule_t;

Nun kann man den Parser selbst definieren. Dies ist z.B. bei kleineren Grammatiken die nicht oft aufgerufen werden direkt in der Methode die das parsen übernimmt, möglich.
Fangen wir mit den Regeln (nonterminals) an:

InstantiatedTypeParser::parse(char marker, const std::string&amp; instantiatedType)
{
rule_t path_sep;
rule_t identifier;
rule_t path;
rule_t single_type;
rule_t instantiated_type_list;i

und hier die eigentliche Grammatik, der EBNF-Form nicht unähnlich:

path_sep = token_node_d[(ch_p(':') >> ch_p(':'))]
           ;
 
identifier = token_node_d[((alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))]
               ;
 
path =	identifier >> *(path_sep >> identifier)
          ;
 
single_type =	path     >> ch_p(m_startMarker)
				>> path
				>> ch_p(m_endMarker)
                    ;
 
instantiated_type_list =	single_type
					|
					path  >> ch_p(m_startMarker)
						>> instantiated_type_list
						>> ch_p(m_endMarker)
                                        ;

Hier der eigentliche Aufruf des parser:

const char* first = instantiatedType.c_str();
tree_parse_info<> info = pt_parse(first, instantiated_type_list, space_p);

Das zurückgegebene Objekt vom Type tree_parse_info gibt nun Auskunft darüber, ob die Eingabe komplett gelesen wurde (was bedeutet, dass sie syntaktisch korrekt ist) oder ob ein Fehler aufgetreten ist. Eine Fehlerbehandlung könnte z.B. so aussehen:

if (info.full)
{
    evaluate(path.id(), identifier.id(), result, info.trees.begin());
}
else
{
    std::ostringstream msg;
    msg << "Invalid syntax in instantiated type '" << instantiatedType
	  << "' at character position " << (info.stop - first) + 1
	  <<". Invalid character: '" << *info.stop
	  << "'.";
    throw std::runtime_error(msg.str());
}

Falls das parsen erfolgreich war, kann dem zurückgegeben tree_parse_info-Objekt der komplette parse tree entnommen und verarbeitet werden. Die Struktur und Beschreibung des parse trees ist ziemlich kompliziert und ich fand es hilfreich, mir von spirit ein xml-Dokument aus dem parse tree erzeugen zu lassen um ihn besser zu verstehen:

std::map
 rule_names;
rule_names[path_sep.id()] = "pathsep";
rule_names[path.id()] = "path";
rule_names[identifier.id()] = "identifier";
rule_names[single_type.id()] = "single_type";
rule_names[instantiated_type_list.id()] = "instantiated_type_list";
tree_to_xml(std::cout, info.trees, first, rule_names);

Dies macht es leichter eine Methode zu schreiben, die den parse tree auswertet. In unserem Beispiel sieht diese Methode so aus:

/**
 *	Processes the parse tree returned by the spirit tree parser.
 *	The parse tree is not intuitively to understand.
 *
 *	We use a tree parser instead of semantic actions because the grammar is
 *	ambiguous and semantic actions cannot easily be undone during
 *	backtracking.
 */
void evaluate(const parser_id&amp; parentId,
			  const parser_id&amp; childId,
			  et::ocl::InstantiatedTypeParser::TypeList&amp; result,
			  const iter_t&amp; node)
{
if (node->value.id() == parentId)
{
	std::ostringstream path;
	/*
	 *	Collect all child nodes of type childId.
	 *	These are the actual identifiers.
	 */
	for (iter_t child = node->children.begin();
	     child != node->children.end();
	     ++child)
	{
		if (child->value.id() == childId)
		{
			/*
			 *	Look at the xml parse tree to understand the
			 *	following code.
			 *	For unknown reasons, the parse tree contains
			 *	always two nested nodes for an identifier rule
			 *	and only the child node contains the actual
			 *	identifier.
			 */
			assert(child->children[0].value.id() == childId);
			std::string value(child->children[0].value.begin(),
					       child->children[0].value.end());
 
			if (path.str().size() > 0)
			{
				path << "::";
			}
			path << value;
		}
	}
 
	std::string p = path.str();
	et::base::trim(p);
	result.push_back(p);
}
 
for (iter_t child = node->children.begin();
      child != node->children.end();
      ++child)
{
	evaluate(parentId, childId, result, child);
}
}

Insgesamt würde ich sagen dass boost::spirit eine echte Alternative ist wenn man einen kleinen Parser in eine C++ Anwendung integrieren möchte. Bei komplexeren Grammatiken würde ich einem richtigen parser generator wie ANTLR den Vorzug geben.

Noch eine Anmerkung: wenn man das warning level in Visual Studio sinnvollerweise auf 4 setzt und ebenso sinnvollerweise die Option “Warnings as errors” aktiviert, verursacht die Spirit header files warnings die zu einem Abbruch des builds führen. Abhilfe schafft es, für die Dateien die diese header files einbinden, die Warnungen 4512, 4127 und 4996 zu deaktivieren.

Technorati Tags: , , ,


Viele Grüße,
Andreas

IT Recht Ressourcen im Internet

July 28th, 2008

Hallo,

im IT Freelancer Heft 4/2008 wird auf zwei Webseiten mit Informationen zum Thema IT-Recht hingewiesen:

Arbeitsgemeinschaft Informationstechnologie im Deutschen Anwaltsverein (DAVIT)

Bayreuther Arbeitskreis für IT – Neue Medien – Recht (AKIT)

Nachdem derartige Ressourcen potentiell nützlich sind, habe ich einen Blick darauf geworden, leider mit enttäuschendem Ergebnis. Beider Websites scheinen primär den Interessen der Mitglieder zu dienen und bieten kaum brauchbare Informationen für Selbständige in der IT.

Um dies etwas zu objektivieren, habe ich den Begriff “Viren” in die jeweiligen Suchfelder eingegeben. Hier hätte ich z. B. Informationen erwartet, wann man bei der unbeabsichtigten Verbreitung von Viren – z.B. über emails – verantwortlich ist und eine rechtliche Relevanz entsteht.

Während die Suchmaschinen von DAVIT immerhin keine Treffer brachte, brachte die Suche bei AKIT völlig irrelevante Treffer die über eine phonetische Suche gefunden wurden. Dafür waren die bezahlten Anzeigen relevant, Google sei dank.

Viele Grüße,
Andreas

Anzeige von source code mit syntax highlighting in blog posts (wp-syntax)

July 28th, 2008

Hallo,

ich wollte schon länger ein plugin für mein blog installieren, mit dem ich source code besser darstellen kann. Ich habe jetzt wp-syntax installiert und bin recht zufrieden damit. Die Benutzung ist einfach und das Ergebnis ist ansprechend (Beispiel). Kleines goodie am Rande: das plugin setzt Sonderzeichen wie etwa < oder > automatisch in HTML entities um.

Ich musste eine Kleinigkeit im source code ändern:

include_once("geshi/geshi.php");

wird zu

include_once("absoluter Pfad zum plugin Verzeichnis/geshi/geshi.php");

Sonst wurde versucht die Datei unter /user/share/php zu laden.

Wer’s nutzt möge nicht vergessen, eine Kleinigkeit für den Autor zu spenden.

Viele Grüße,
Andreas

Technorati Tags: , ,

Erstellung von Parsern in C++ mit der boost::spirit library

July 21st, 2008

Hallo!

In der Softwareentwicklung steht man regelmäßig vor der Aufgabe, eine Eingabe nach gewissen Regeln zu verarbeiten. Dazu bedient man sich in einfachen Fällen regulärer Ausdrücke, die man in C++ z.B. mit der boost::regex library verarbeiten kann. Wenn die Struktur der Eingabe zu komplex ist, definiert man eine Grammatik und verwendet einen Parser Generator wie lex/yacc oder ANTLR (wobei man in diesem Fall vorsichtig sein muss. Für die aktuelle Version 3.0 ist zum Zeitpunkt der Veröffentlichung dieses postings immer noch kein brauchbares C++ target verfügbar).

Reguläre Ausdrücke sind allerdings schwer zu lesen und eignen sich schlecht für rekursive Strukturen.

Einen Parser Generator aufzusetzen und in ein C++-Projekt einzubinden ist wiederum etwas lästig. Insbesondere wenn man verschiedene Plattformen (etwa, Visual C++ und MinGW unter Windows und gcc unter Linux) unterstützt, wiederholt sich der Aufwand.

Mit der boost::spirit library gibt es noch einen Weg dazwischen, der genau diese Lücke füllt. Man kann mit richtigen Grammatiken arbeiten und braucht trotzdem kein externes tool einzubinden.

Da die Arbeit mit Spirit nicht ganz trivial ist, wollte ich meine Erfahrungen anhand eines kleinen Beispiels festhalten und weitergeben.

Die zu lösende Aufgabe bestand darin, einen String zu parsen, der einen “instantiierten Typ” – i.A. template oder generic genannt – verarbeitet und die verwendeten Typen als Liste zurückgibt. Dabei sollten die in den gängigen Programmiersprachen üblichen Regeln für identifier berücksichtigt werden und die Eingabe sollte wie sonst üblich formatfrei sein, d.h. white space sollte ignoriert werden.

Beispiele für gültige Eingaben wären dann:

Set(String)
Set(Bag(String))
Set ( String )
My_Container1(Integer)

Eine solche Aufgabe ist genau von der richtigen Komplexität für boost::spirit.

Falls sich jemand über die runden Klammern wundert (üblich sind spitze Klammern) – der Parser soll im Kontext der Object Constraint Language (OCL) verwendet werden und dort werden runde Klammern verwendet. Dies ist aber ein irrelevantes Detail.

Spirit ist auf möglichst flexible Verwendbarkeit ausgelegt, es gibt verschiedene alternative Verfahren und es werden intensiv “Policy-Klassen” in der Form von template-Parametern verwendet.
Dies macht die Verwendung nicht gerade leichter, da es sehr viele mögliche Kombinationen der Verfahren und Policies gibt. Deshalb soll dieses posting auch eine Art Kochbuch sein, dass typische Anforderungen abdeckt. Gängige Beispiele wie etwa hier verwenden “semantic actions”, die direkt beim match einer Regel ausgeführt werden. Dieses Vorgehen hat einen grossen Nachteil, der es für viele Fälle unbrauchbar macht: bei einer mehrdeutigen Grammatik, wie sie in der Praxis häufig vorkommen, versucht der Parser durch “probieren” eine zur Eingabe passende Regel zu finden. Falls dies nicht klappt wird der Versuch abgebrochen und nochmal von vorne begonnen (”backtracking“). Dummerweise werden semantic actions die mit einer Regel assoziiert sind bei jedem versuchten match aufgerufen. Es kann aber sein, dass diese Aufrufe gar nicht relevant sind, weil der Parser später erkennt dass die aktuelle Regel nicht matcht und ein backtracking vornimmt.

Spirit bietet die Möglichkeit einen “tree parser” zu verwenden, der dieses Problem nicht hat. Ein solcher tree parser liefert einen Syntax Baum der immer gleich aussieht und exakt der Eingabe entspricht, unabhängig davon wie oft ein backtracking auftrat. Davon abgesehen ist es generell eine gute Idee, die Grammatik von der semantischen Verarbeitung zu trennen, was mit einem tree parser implizit gegeben ist.
Zusammenfassend würde ich also bei der Verwendung von Spirit immer einen Tree Parser empfehlen.

Angesichts der schweren Zugänglichkeit von Spirit ist man für Beispiele immer dankbar, z.B. hier für die Verwendung eines tree parsers. Wenn man sich an diesem Beispiel anlehnt, wird man aber feststellen, dass der Parser white space nicht ignoriert, ein Verhalten dass im allgemeinen unerwünscht ist. Die Lösung besteht darin, die Zeile

typedef scanner_policies<iteration_policy, match_policy_t, action_policy> scanner_policy_t;

in

typedef scanner_policies<skip_parser_iteration_policy<space_parser>, match_policy_t, action_policy> scanner_policy_t;

zu ändern. Auch wenn man herausgefunden hat, dass der erste template Parameter, die “iteration policy”, für das ignorieren von white space zuständig ist, ist es noch ein weiter Weg bis man den korrekten Wert kennt den man für diese policy angeben muss.

Nachdem ich in diesem posting die wichtige Festlegung auf einen tree parser empfohlen habe und die Hürde des ungünstigen Beispiels eines parser der white space nicht ignoriert genommen habe, werde ich im nächsten posting den konkreten code und insbesondere die Definition der Grammatik zeigen.

Knifflig wird es dann wieder beim Auswerten des parse trees, was leider keine triviale Aufgabe ist.

Viele Grüße,
Andreas

Technorati Tags: , ,

GI-Jahrestagung INFORMATIK 2008 in München

June 22nd, 2008

Hallo,

vom 08.-13.09.2008 findet in München wieder die GI-Jahrestagung INFORMATIK 2008 statt.

Solche nicht kommerziellen Kongresse bieten gerade Selbständigen die ihre Fortbildung selbst bezahlen müssen eine kostengünstige Möglichkeit über den Tellerrand des täglichen Jobs zu schauen, etwas neues zu lernen oder einfache wieder mal neue Motiviation für die Softwareentwicklung und Informatik zu tanken.

Wie man auf der Anmeldeseite sieht, gibt es ein breites Spektrum von Veranstaltungen und Buchungsoptionen.

Selbständige Softwareentwickler möchte ich besonders auf den IT Freelancer Kongress hinweisen, in dem es nicht um Softwareentwicklung sondern um Marketing- und rechtliche Aspekte einer selbständigen Tätigkeit im IT-Bereich geht.

Wenn ich zu dieser Zeit nicht in Urlaub wäre, würde ich sicher einen Tag teilnehmen, z.B. bei der Veranstaltung Anwendungslandschaften in Banken und Versicherungen.

Viele Grüße,
Andreas

Technorati Tags:

Bundesverfassungsgericht: Gewerbesteuerfreiheit von Freiberuflern verfassungsgemäß

June 12th, 2008

Hallo,

im letzten Newsletter für Freiberufler der Gesellschaft für Informatik (GI) hat Ulrich Bode wieder einige interessante news zusammengetragen, unter anderem zum Thema Gewerbesteuerpflicht für Freiberufler (Zitat):

Bundesverfassungsgericht: Gewerbesteuerfreiheit von Freiberuflern verfassungsgemäß

Das Bundesverfassungsgericht hat die Gewerbesteuerfreiheit von Freiberuflern für verfassungsgemäß erklärt. In der Begründung führt das Gericht aus, dass die Gewerbesteuer ein pauschaler Ausgleich für die gewerbliche Infrastruktur einer Gemeinde sei. Diese sei für Freiberufler typischerweise nicht erforderlich. Folglich kann der Gesetzgeber die Freiberufler von der Gewerbesteuer ausnehmen.

Das Gericht hat das Urteil in einer lesenswerten Pressemitteilung auf
http://www.bundesverfassungsgericht.de/pressemitteilungen/bvg08-058.html
zusammen gefasst.

Das Urteil selbst ist auf
http://www.bverfg.de/entscheidungen/ls20080115_1bvl000204.html
zu finden.

Das ist doch mal eine gute Nachricht.

Ebenfalls hingewiesen wurde auf eine kostenlose Software für Freiberufler: www.freelaxer.com
Sieht sehr professionell aus. Wer lediglich eine gute Zeiterfassung braucht – z.B. weil er in der Regel längerfristig für den gleichen Kunden arbeitet und nur einmal im Monat eine Rechnung stellt – kann sich ja mal Timicx anschauen.

Viele Grüße,
Andreas

Technorati Tags: , ,

Formatierter source code in Microsoft Word

June 8th, 2008

Hallo,

bis vor kurzem war mir nicht bewusst, das beim Kopieren und Einfügen von source code zwischen Visual Studio und Microsoft Word die Formatierung erhalten bleibt.

Ich nehme an, Visual Studio legt den code (unter anderem) im RTF-Format im Clipboard ab.

Das ist eine ziemlich einfache Möglichkeit, Code-Beispiele in Word-Dokumente einzufügen.

Formatted source code in Microsoft Word

Dieses Verfahren funktioniert übrigens auch mit Eclipse.

Viele Grüße,
Andreas

Technorati Tags: ,

Die Bedeutung der UML

June 4th, 2008

Hallo,

in diesem Artikel wurde die These postuliert, dass UML nicht mehr relevant sei und aus verschiedenen Gründen von “Programmierern” ignoriert würde.

Dieses posting hat eine lebhafte Diskussion ausgelöst, z.B. auf slashdot, Raval Chaves blog und Google groups. Auch ich habe auf meinem Firmenblog einen kleinen Beitrag dazu geschrieben.

Viele Grüsse,
Andreas

Technorati Tags:

Visualisierung von Softwarearchitekturen mit Doxygen

May 18th, 2008

Hallo,

in diesem posting geht es zwar um UML aber ich war erstaunt wie viele Kommentar sich auf Doxgyen als Werkzeug zu Visualisierung von Softwarearchitekturen bezogen.

Ich selbst habe mit Doxygen ebenfalls schon sehr gute Erfahrungen beim Verstehen fremden codes gemacht. Doxygen analysiert den code mit einem Minimum an Konfiguration, geht dabei “best effort” vor und produziert bei entsprechender Konfiguration eine Reihe hilfreicher Artefakte:

  • Collaboration graph: zeigt welche Klassen von einer Klasse benutzt werden, z.B. als member
  • Inheritance graph: zeigt von welchen Klassen eine gegebene Klasse abgeleitet ist aber auch welche Klassen von der gegebenen Klasse abgeleitet sind
  • Static call hierarchy graph: zeigt (rekursiv) an, welche Methoden in einer bestimmten Methode gerufen werden
  • References/referenced by: zeigt an welche anderen Methoden eine Methode benutzt und wo eine Methode benutzt wird (cross reference Dokumentation)
  • Include graph: illustriert die Schachtelung von include-Anweisungen in C/C++
  • Verlinkter source code: Doxygen erzeugt formatierten source code mit syntax highlighting. Methoden und Datentypen sind verlinkt so dass man mit einem Mausklick zu der Methode oder Definition des Datentyps springen kann.

Beim reverse engineering mit einem UML tool wird in der Regel nur das repository selbst erzeugt und ggf. ein großes Diagramm mit allen importierten Elementen, was nicht viel bringt. Graphen wie etwa die statische Aufrufhierchie einer Methode erzeugen diese tools überhaupt nicht.

Hier ist ein Beispiel, entnommen von der Doxygen-Dokumentation des Tahoe-Projektes.

In diesem Artikel ging es primär um die Reengineering-Fähigkeiten von Doxygen, der Fokus dieses tools ist aber eigentlich die Aufbereitung bon inline-Dokumentation die von den Autoren der Software erstellt wurde.

Highly recommended!

Viele Grüsse,
Andreas

Technorati Tags: ,