Buchrezension: Build Awesome Command-Line Applications with Ruby 2

Veröffentlicht von am 9. Juli 2014 in Buchrezensionen

Leider ein wenig arg verspätet (Umzug, Studium, Arbeit und Familie) kommt hier nun endlich die Rezension zum Buch „Build Awesome Command-Line Applications in Ruby 2“ von David Bryant Copeland, ein Buch, das beim Verlag „The Pragmatic Programmers“ unter der Serie „The Facets of Ruby“ veröffentlicht, und vom O’Reilly-Verlag vertrieben wird, der uns dieses Exemplar in englischer Sprache freundlicherweise zur Rezension zur Verfügung gestellt hat.

Lesemotivation und Überblick

dccar2Als Rails-Direkteinsteiger (siehe auch meine vorherige Rezension) war ich sehr interessiert an diesem Buch, und erhoffte mir, auch ein paar Ruby-Grundlagen abseits der Rails Umgebung zu erlangen. Insbesondere da der Titel Ruby 2, also die aktuellste Version von Ruby hervorhebt, war ich gespannt zu sehen, was sich zu den Vorgängern verändert hat, denn nach allen Change-Notes ist der Unterschied zwischen 1.9 und 2.0 doch sehr gering. Hier, das möchte ich schon mal vorwegnehmen, hat mich das Buch ein wenig enttäuscht, wenn es auch ansonsten sehr lesenswert war. Der Fokus liegt nämlich ausschließlich auf dem „Awesome Command-Line Applications“; soweit ich das überblicken kann, ist dabei kaum etwas Ruby 2 spezifisch und auch ansonsten hat sich nicht viel zur ersten Version geändert. Nichtsdestotrotz bietet dieses Buch einiges Interessantes. Was das im Detail ist, möchte ich in dieser Rezension erörtern, um somit anderen Lesern Klarheit über das zu Erwartende zu verschaffen.

Konsolen-Tools, im Gegensatz zur Graphical User Interface (GUI) auch Command Line Interface (CLI) genannt, spielen auch heute noch eine wichtige Rolle, was auch Copeland feststellt, welcher die Welt der Programmierer in eine Pre- und Post-Java-Zeit einteilt.

In der Post-Java-Zeit sieht der Autor die CLI immer weiter verdrängt; erst durch das Aufkommen von Ruby und Rails tritt die CLI seiner Meinung nach wieder in den Vordergrund, weshalb er sich in seinem Buch auf die Erstellung von CLI-Tools mithilfe von Ruby konzentriert. Die Verdrängung der Shell durch die GUI und die Maus wird auch in einem kleinen Werbevideo zum Buch zum Ausdruck gebracht, welches ich euch nicht vorenthalten möchte, da es doch ganz niedlich ist.

Copeland macht zwei Stile von CLI Applikationen aus, die einfachen UNIX-ähnlichen und die komplexen Command-suites, unter welche er Tools wie git oder gem fasst.

Für beide Arten von Applikationen beschreibt Copeland den Entwicklungsprozess. Dabei führt er zwei Beispiel-Probleme ein,  zum einen ein Skript, welches Sicherheitskopien für eine Datenbank erstellt, zum andern ein Tool, welches eine Todo-Liste verwalten soll. Beide Tools sollen mit viel Komfort bedient werden können, d.h. bspw. soll das Backup-Skript zwischen vollständigen und iterativen Backups differenzieren, diese komprimiert ablegen und nicht mehr benötigte iterative Backups automatisch löschen; die Todo-Liste soll mitschneiden, wann ein Punkt hinzugefügt und abgehakt wurde, und verschiedene Darstellungen unterstützen. Diese Programme werden in einer ersten rudimentären Version ausprogrammiert, ab dann werden allerdings nur noch Fingerzeige auf die wichtigsten Codeteile geliefert, sodass für ein lauffähiges Programm auch Eigenarbeit hineingesteckt werden muss, wenn man die Beispiele auch selbst implementiert. Allerdings gelingt es dem Autor so, die Beispiele klein und gut lesbar zu halten und den Fokus des Lesers sehr genau lediglich auf den relevanten Teil des Codes zu legen.

So schafft es Copeland auf nur 170 Seiten in 10 Kapiteln unterteilt, einen relativ kompletten, wenn auch nicht ausführlichen Überblick über die Entwicklung von CLI-Programmen zu geben und dabei sowohl Programmiermethoden und Werkzeuge als auch Theorien und Best-Practices vorzustellen.

Inhalt

Im Kapitel 1 stellt Copeland die zwei oben beschriebenen Programme vor und arbeitet dabei heraus, dass ein „Clear and Concise Purpose“ nicht für jedes Problem dasselbe bedeutet, dieses aber in jedem Fall zuvor erarbeitet werden sollte, da nur so auch sicher gestellt werden kann, dass das CLI-Programm awesome wird und auch mit anderen CLI-Tools zusammen arbeiten kann. Für den ersten Fall – die Datenbanksicherung – wird gezeigt, dass es wichtig ist, zwischen den eigentlichem Sinn und dem tatsächlichen Problem und der damit verbundenen Konfiguration zu unterscheiden. Beim zweiten Problem steht die Benutzbarkeit und der Datenaustausch so sehr im Vordergrund, dass eine Aufspaltung im Sinne des Single-Purpose-Files (wie im ersten Beispiel noch propagiert) eher kontraproduktiv ist. Hier soll daher eine Command Suite a la git gebaut werden, die mehrere Commandos vereint. Copeland arbeitet dabei noch einmal ganz genau aus, was seinem Verständnis nach eine awesome CLI-App ist:

  • Easy to use
  • Helpful
  • Playing well with others
  • Sensible defaults but high configurability
  • Installs painlessly
  • Fails gracefully
  • Gets new features and bug fixes easily
  • Delights others

Um all diese Punkte soll es dann in den folgenden Kapiteln gehen.

Im 2. Kapitel „Easy to use“ geht Copland auf die etablierten Standards für CLI-Applikationen ein. Dabei wird ein typisches CLI-Tool in seine Bestandteile zerlegt und gezeigt, wie man Optionen in langer und kurzer Form angibt, was der Unterschied zwischen Switches und Flags sind, was Global- und was Command Options sind und woran man Option Arguments von Command Arguments unterscheiden kann. In der Verwendung sollte dies eigentlich jedem geläufig sein, der schon mal mit der Shell zu tun hatte – was für Ruby-Programmierer genau so zutreffen sollte wie für Systemadministratoren. Für das einfache Entwickeln von Applikationen, welche Switches, Flags und Arguments beinhalten, werden zwei interessante Tools vorgestellt:

  1. OptionParser für einfache CLI-Applikationen
  2. GLI für Command Suits; ein Tool das aktiv von Copeland entwickelt wird.

Auf die besondere Bedienung von GLI, welches sich dem aus Rails bekannten Scaffolding bedient um umfangreiche Verzeichnisbäume automatisiert zu erstellen, wird dabei der Fokus gesetzt.

Nachdem beide Applikationen sich so verhalten, wie es von CLI-Tools aus der Unix-Welt erwartet wird, wendet sich Kapitel 3, „Be Helpful“ der Hilfe zu. Es wird gezeigt, wie die Tools OptionParser und GLI dabei helfen, Benutzerhilfen automatisiert zu generieren und gleichzeitig zur Quelltext-Dokumentation eingesetzt werden können. Auch wie man mithilfe der Gems gem-man und ronn Manpages und Dokumentationen erstellt, wird dargelegt. Danach folgen auf 5 Seiten Hinweise zum Unterthema „Writing Good Help Text and Documentation“.

„Playing well with others“ heißt das darauf folgende Kapitel 4 und dieses arbeitet heraus, wie wichtig es ist, dass der Benutzer nur als Teil der Applikation zu betrachten ist. Genau so wichtig ist es, dass die Applikation auch einfach von anderen Programmen genutzt werden kann. Beispielsweise sollte die Datenbank-Sicherung auch von einem Scheduler wie cron zur regelmäßigen, automatischen Sicherung aufgerufen werden können. Aber auch das Nutzen von anderen Tools wird thematisiert. So nutzt auch das Datenbank-Skript externe CLI-Tools wie mysqldump und gzip. Mit welchen Programmen ein Tool zusammen arbeiten soll, ist im Vorhinein meist unbekannt. Copeland zeigt anhand von „ExitCodes“, „ExitStauts“, „Standard Output“ und „Error Stream“, wie Applikationen dennoch über standardisierte Wege miteinander kommunizieren können, ohne sich zu kennen. Außerdem zeigt er, wie Prozesse mittels Signals auch zur Laufzeit Daten austauschen.

Kapitel 5, „Delight Casual Users“ hebt hervor, wie wichtig sprechende Namen sind und wie wichtig auch die Langform von Switches und Flags sind. Langformen sollen sprechend sein, die Kurzformen sinnvolle Mnemonics – insgesamt soll das Tool aber einfach und intuitiv beherrschbar sein. Dabei wird sich auch an bekannten Standards aus der Unix-Welt orientiert und es wird erörtert, wie man gute Default-Werte für sinnvolles Standardverhalten festlegen kann.

Nachdem Kapitel 3 bis Kapitel 5 eher theoretischer Natur waren, geht es in Kapitel 6 wieder vermehrt technisch ans Werk. In „Make Configuration Easy“ wird YAML vorgestellt und die Vorteile gegenüber klassischer XML-Konfiguration dargelegt. Dann werden die Beispiel-Applikationen dahingehend verändert, dass sie neben einer Standardkonfiguration im Code auch eine manuelle Konfigurationsdatei in YAML einlesen, sowie auch Standardkonfigurationen für den Nutzer automatisiert anlegen und
einlesen können.

Im 7. Kapitel, „Distribute Painlessly“ wird ein ganzes Sammelsurium an Tools vorgestellt, um Quelltexte und Programme zu verteilen. Zunächst werden die RubyGems vorgestellt, das Standardtool für die Verbreitung von Ruby-Code. Es wird gezeigt, wie der Aufbau einer Gem Specification aussieht und für das Todo-Programm ein solches geschrieben. Dann wird gezeigt, wie man mit dem build-automisation Tool rake (benannt nach dem bekannten GNU make) den Packprozess vereinfacht. Danach wird das entstandene Gem auf https://rubygems.orgDER Quelle für RubyGems – gehostet. Es wird aber auch dargestellt, wie man sich einen eigenen Gem Server (lokal) einrichten kann, wenn die Gems nicht über die Standardseite, oder nur für einen lokalen Bereich zur Verfügung stehen sollen. Besonders interessant finde ich, dass daneben auch auf alternative Verbreitungsmöglichkeiten kurz eingegangen wird. So wird unter anderem auch gem2rpm vorgestellt, welches das Ruby-Programm in dem RedHat Package Manager-Format verpackt, dass für viele Linux-Systeme (bspw. OpenSuse, Fedora, CentOS) zur verfügung steht. Weitere Tools die vorgestellt werden sind bundler, rdoc, git und GitHub.

Meiner Meinung nach falsch platziert kommt erst in Kapitel 8 das so wichtige Thema „Test, Test, Test“. Copeland geht in dem kurzen Kapitel (das ganze Bücher füllen kann) einerseits auf das Acceptance Testing mithilfe von Cucumber und Aruba (Cucumber für Windows) ein, um das Verhalten der gesamten Applikation zu testen, anderseits beleuchtet er das isolierte Testen einzelner Code-Einheiten mithilfe von Test::Unit und dem Mocha Framework. Das Ruby das Test-Driven Development von Natur aus unterstützt und daher die Tests eigentlich als erstes geschrieben werden sollten, verschweigt Copeland nicht und verweist hier auf wichtige weiterführende Literatur.

Kapitel 9, „Be Easy to Maintain“, geht in Kürze noch mal einige Best-Practices der Programmierung durch, etwa, dass man seinen Code auf mehrere logische Dateien aufteilen sollte, dass Daten und Methoden in sinnvolle Klassen zusammengefasst werden sollten, dass zusammengehörige Klassen in sinnvolle Namespaces gebündelt werden sollten, dass jede Datei wie die beinhaltende Klasse heißen sollte, und dass man, wenn möglich, auf Design Patterns zurück greifen sollte, von denen zwei kurz angerissen werden.

Im  letzten Kapitel „Add Color, Formatting and Interactivity“ zeigt uns Copeland dann, wie wir unser Programm dahingehend optimieren, dass der Benutzer ein angenehmes Bedienerlebnis bekommt. Dazu wird auf die ANSI-Eescape Sequenzen eingegangen und gezeigt, wie diese mittels dem Gem rainbow einfach genutzt werden können. Außerdem wird mit dem Gem terminal-table die Ausgabe in Tabellen gesetzt. Und zuletzt wird mit readline dargestellt, wie die Benutzereingabe mit einer Prompt versehen wird, sodass Daten interaktiv abgefragt werden können und dem Benutzer eine History und Tab-Completion geboten wird.

Zielgruppe?!

Bevor ich zum Fazit komme, möchte ich kurz einige Worte über die Zielgruppe verlieren. Auch wenn Copeland schreibt, dass dieses Buch sowohl für Entwickler als auch für Systemadministratoren gedacht ist, die nur geringes Vorwissen in Ruby mitbringen müssen, habe ich mich während des Lesens des Öfteren gefragt, für wen Copeland ein bestimmtes Kapitel wohl gerade schreibt.

Ideal wäre es wahrscheinlich für Menschen, die bisher nur GUIs geschrieben haben und noch nie mit der Shell gearbeitet haben. Dies ist unter Ruby-Programmierern eigentlich schon systembedingt unvorstellbar. Insofern können die Bereiche über den Aufbau von CLI-Tools in ihrer Ausführlichkeit nicht für den Ruby-Programmierer gedacht sein; trotzdem muss man Ruby-Vorwissen mitbringen.

Für Systemadministratoren, die nur wenig Erfahrungen im Programmieren mit Ruby haben, sind die Code-Beschreibungen dann teilweise doch sehr kurz gefasst. Auf die Programmiersprache Ruby als solche wird kaum eingegangen. Einiges wird man sich sicherlich herleiten können, wenn man erfahren in Perl oder Python ist. Ideal wäre es jedoch, wenn Ruby schon besser beherrscht wird, da auf die Eigenheiten von Ruby nicht eingegangen wird; das finde ich ein wenig schade, denn Systemadministratoren kommen klassischer Weise eher mit Perl und bash in Kontakt und da kann Ruby an mancher stelle doch recht verwirrend sein. Für den Fall, dass man Ruby jedoch kennt sind Kapitel wie „Distribute Painlessly“ oder „Test, Test, Test“, welche klassische Themen der Ruby-Programmierung adressieren, wahrscheinlich wieder unnütz.

Insofern hat das Buch in meinen Augen keine klassische und gut umrissene Zielgruppe, für welche man dieses Buch uneingeschränkt empfehlen kann; jeder Leser wird sich seine Kapitel herauspicken müssen und sich damit abfinden, dass er einen nicht unwesentlichen Teil einfach überblättern kann. Dennoch finde ich, dass das Hineinschauen in das Buch insgesamt durchaus zu empfehlen ist. Copeland hebt immerzu hervor, was ein gutes CLI-Tool ausmacht und legt dabei Augenmerk auf benutzerfreundliche CLI. Als Freund von CLI-Tools kann ich dieses Buch also nur jedem ans Herz legen, insbesondere wenn man noch nie ein CLI-Tool geschrieben hat, da einem hier gezeigt wird, wie einfach mächtige CLI-Programme in Ruby formuliert werden können; oder aber wenn man sein erstes umfangreicheres CLI-Tool schreiben möchte – denn hierfür finden sich im Buch auch viele wertvolle Hinweise. Und auch als erfahrener (Ruby-)Programmierer lernt man mit OptionParser, GLI, oder readline eventuell neue Frameworks kennen, die beim Erzeugen von CLI unterstützen. Als Sammlung wertvoller und interessanter Gems nützt dieses Buch also allemale – auch für mich waren hier einige interessante Sachen dabei.

Fazit

Insgesamt liest sich das Buch sehr schnell und einfach, die Beispiele sind simpel gehalten und auf das Wesentliche reduziert, weswegen das Buch recht Textlastig und nur wenig technisch ist. Wenn man Ruby einigermaßen beherrscht, so lässt sich das Buch als Abendlektüre verwenden; man muss die Codebeispiele nicht austesten um dem ganzen folgen zu können. Trotz der einfachen Beispiele schafft Copeland es, auf die wichtigsten Themen bei der Entwicklung von CLI-Tools mit Ruby einzugehen und mithilfe der Beispiele auch einen stabilen Entwicklungsprozess in allen Stadien zu skizzieren.

Allerdings bleibt es lediglich bei einer Skizze. Wer noch kaum Erfahrungen mit Ruby hat, kommt um ein gutes Ruby Buch nicht herum; auch die Inter-Prozesskommunikation wird nur angerissen, sodass die gesamte Mächtigkeit nur mithilfe zusätzlicher Bücher (in diesem Fall ein Buch über Unix-Betriebssystem) ausgenutzt werden kann. Auch das wichtige Thema TDD wird nur angerissen; ein ausführliches Buch, dass ich hier zur weiteren Vertiefung empfehlen kann ist (aus der selben Reihe des Verlages) das „RSpec Book“ von Chelimsky et al. Auch Themen wie Git bedürfen eine weit umfangreichere Erklärung als es der Umfang dieses Buches erlaubt.

Vor allem die wertvollen Tips zum Schreiben von stabilen Tools, die eine hohe Benutzerfreundlichkeit aufweisen und flexibel einsetzbar sind, macht dieses Buch dennoch lesenswert, da hier ein Beitrag dazu geleistet wird, dass die CLI auch in Zukunft eine wichtige Alternative zu den GUI Tools bleiben wird, insbesondere in den Bereichen, in denen die CLI auch heute schon nicht von einer GUI verdrängt werden kann.

Es bleibt also insgesamt ein gutes, einfach zu lesendes Buch, das einen guten Einstieg für Leute bietet, die schon ein wenig Programmiererfahrung haben und in die Verlegenheit kommen könnten, auch mal ein gutes CLI-Tool schreiben zu wollen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.