Montag, 30. Juli 2012

Pseudowissenschaft Agilität

imageWas Agilität ist, weiß selbst Martin Fowler nicht zu definieren. Das sagt er in seinem Blogartikel:

[…] lack of rigorousness is part of the defining nature of agile methods, part of its core philosophy. […] Any attempt to define a rigorous process that can be tested for conformance runs contrary to [the agile] philosophy.

Es sei also vergeblich, einen rigorosen Prozess agilen Vorgehens definieren zu wollen. Das entspräche nicht der Philosophie der Agilität, dem agilen Denken.

Ich bin erschüttert.

Was für eine Bankrotterklärung der Agilität! Ausgesprochen von einem Unterzeichner des agilen Manifests.

Damit stellt sich die Agilitätsbewegung das Zeugnis einer Pseudowissenschaft aus: Sie entzieht sich der Falsifizierbarkeit und macht sich vom Urteil von “Geweihten” abhängig. Denn:

  • Wo keine Definition, da kein Vergleich der Realität mit einer Definition und also keine (Miss)Erfolgsmessung. Behauptet jemand, agil zu arbeiten, vermisst jedoch den erhofften Erfolg, dann kann nicht überprüft werden, ob er denn überhaupt und wirklich agil arbeitet. Das erschwert die Implementation agilen Vorgehens. Und das leistet andererseits der Leugnung von Misserfolgen bei agilem Vorgehen Vorschub.
  • Auch wenn es an einer Definition der Agilität mangelt, ja – wie Fowler sagt - mangeln muss, können Martin Fowler und “der erfahrene Praktizierer” dennoch erkennen, ob agil vorgegangen wird. Ohne Definition von Agilität, bedeutet das allerdings eine Kette von “Weihungen” ausgehend von Martin Fowler (oder vielleicht einem anderen Unterzeichner des agilen Manifests). Denn wie sonst könnte jemand zum “erfahrenen Praktizierer” werden? Ohne Definition kann ja niemand selbst feststellen, ob er/sie agil arbeitet.

Definitionslosigkeit und “I know it when I see it” [Zitat Fowler] sind nun leider die besten Voraussetzungen für Fundamentalismus, Dogma, Abgeschlossenheit, Kritikimmunität.

Nicht, dass wir davon in den vergangenen Jahren nicht schon Anzeichen gesehen hätten. Die Diskussionen mit Agilitätsvertretern konnten immer schon, hm, “intensiv” werden… Aber dass nun der Martin Fowler dafür die Rechtfertigung liefert… Nein, das kann ich kaum fassen.

Was sollen denn jetzt Laien von der Softwareentwicklung denken? Was sollen angehende Informatikstudenten von der Agilität denken? Ich kann das schenkelklopfende Lachen in Universitäten wie Chefetagen schon hören. “Was haben sich die Softwarefuzzis da denn ausgedacht? Meinen, mit dieser agilen Mode etwas besser zu machen – und wissen dann nicht mal zu sagen, was es ist? [ROFL]”

Die Alternative: Wissenschaftlichkeit

Wenn Martin Fowler es nur schwer fiele, Agilität bzw. agiles Vorgehen zu definieren, dann wäre ich ganz bei ihm. Vom agilen Manifest bis zu einer Definition und dann auch noch der Messung des Erfolges von Implementationen dieser Definition… das ist ein weiter Weg.

Doch auch wenn es sich schwierig ausnimmt, sollte man es nicht unversucht lassen, glaube ich. So ist das halt mit der Wissenschaftlichkeit.

imageNur mit einem wissenschaftlichen Ansatz kann die Agilität (oder auch Lean usw.) hoffen, jenseits von Glaubensbekenntnissen und Hype und anekdotischen Erfolgen ernst genommen zu werden. All die, auf die sich auch Agilisten gern berufen – von Turing über Parnass bis Kay – sind Wissenschaftler (gewesen). Es stünde der Agilität daher gut zu Gesicht, sich vertrauensvoll in deren Tradition zu stellen. Das heißt, die Agilitätsbewegung müsste ihre Methode oder Philosophie als Hypothese anerkennen.

Denn mehr ist es nicht, was das agile Manifest und alles, was zur Agilität geschrieben wurde, darstellt: eine bloße Behauptung.

Eine wie auch immer (nicht) definierte Methode und Philosophie steht im Raum; ein mehr oder weniger schwammiges Erfolgsversprechen ist daran geknüpft. Und das gilt es nun auf Wahrheit zu überprüfen. Ganz ergebnisoffen. So ist das mit der Wissenschaftlichkeit.

Was immer Agilisten auch behaupten mögen, ist ja ok. Da gibt es keine Grenzen. Das mag grob oder fein sein, konzeptionell oder technologisch, abstrakt oder konkret… Egal. Nur steckt in der Behauptung eben noch keine allgemein akzeptierbare Wahrheit. Die muss erst in einem Diskurs und durch Experimente entwickelt werden. Dazu gehört natürlich eine Messlatte. Das ist eine klare Definition inkl. Ergebniserwartung. Die müssen vorliegen, bevor ein Experiment gemacht wird.

Und dann… dann schaut man, ob die Definition im Experiment implementiert wurde und das vorhergesagte Ergebnis eingetreten ist. Vielleicht hat es geklappt, vielleicht nicht. Dann ist Ursachenforschung zu betreiben. Dabei kann herauskommen, dass die Hypothese angepasst werden muss. Und vielleicht kommt dadurch heraus, dass die Agilität nicht so einfach heilsbringend ist, wie sie gern möchte. Es kann also passieren, dass auch Agilisten etwas lernen müssen.

Aber ist das nicht normal? Ist das nicht im Grunde im Sinne der Agilität? Ach so, das kann man nicht so genau wissen. Denn es gibt ja keine allgemeine Definition.

Fazit

Ich halte ja eine ganze Menge von der Agilität. (Jedenfalls von der, für die ich meine eigene kleine Definition habe. Ob und inwiefern die allerdings mit dem “Gefühl” von Martin Fowler übereinstimmt, weiß ich natürlich nicht. Ich bin von ihm nicht “geweiht”.) Aber ich sehe eine große Gefahr für die Agilität heraufziehen, wenn Martin Fowlers Position allgemein akzeptiert wird. Der Dogmatisierung ist dann nichts mehr entgegen zu setzen. Und das würde sie diskreditieren.

“Die Agilität” täte aus meiner Sicht also gut daran, alle Anzeichen von Immunisierung und Unwissenschaftlichkeit zu zerstreuen. Das mag weh tun, wenn man sich denn endlich mal hinsetzen muss für eine Definition… aber es hilft halt nichts. Auch im Definitionsschmerz kann eine wertvolle Erkenntnis stecken.


PS: Hm… Nun kann es natürlich sein, dass Martin Fowler & Co nicht daran interessiert sind, die Agilität wissenschaftlich zu machen oder einfacher: überprüfbar zu gestalten. Wenn das so ist, na, dann müssen sie das nicht tun. Nur dürfen sie sich dann aber auch nicht darüber beklagen, dass die Ergebnisse gemischt ausfallen und Akzeptanz auf der Strecke bleibt. Wer nicht genau sagen kann, was er meint, der kann eben auch nicht verstanden werden.

Dasselbe gilt übrigens für die Objektorientierung, würde ich sagen. Oder auch SOA. Mit ihnen stehen auch Hypothesen im Raum. Versprechen wurden mehr oder weniger genau, in jedem Fall blumig gegeben. Die Überprüfung allerdings, die fällt schwer.


PPS: Und was ist mit der Clean Code Developer Initiative? Verspricht die nicht auch etwas? Stellt sie nicht auch eine Hypothese dar? Klar. Aber erstens scheuen wir uns bei CCD nicht vor eine Definition. Schon gar nicht glauben wir, dass es CCD inhärent sei, einer Definition zu widerstehen. Zweitens scheint uns die Hypothese von CCD schon recht klar:

  • Das Wiki definiert, was man tun muss, um ein CCD Experiment zu starten: Folge den Prinzipien, setze die Praktiken ein. Je mehr, desto besser. Ob das passiert, lässt sich auch von “Ungeweihten” nachvollziehbar feststellen :-)
  • Das Wiki formuliert (implizit) als Hypothese: Die Korrektheit, Evolvierbarkeit und Produktionseffizienz steigen, wenn man den Prinzipien und Praktiken folgt. Auch das lässt sich von “Ungeweihten” nachvollziehbar feststellen :-)

Sicherlich könnte die Hypothese noch klarer werden. Wer dazu beitragen will, ist herzlich eingeladen. Grundsätzlich empfinden wir uns aber schon auf dem wissenschaftlichen Weg. Und wenn wir CCD damit “angreifbar” (falsifizierbar) machen, dann ist das völlig ok. Wir stellen das Ziel “bessere Software” über den Weg.

Montag, 23. Juli 2012

Was andere schon richtig machen – Prinzipien

imageDas ist Wolfgang Marlie. Er ist Inhaber der Reiterpension Marlie an der Ostsee - und Reitlehrer aus Passion [1]. Von ihm können wir als Softwareentwickler etwas lernen.

Als Reitlehrer ist seine Aufgabe, Reitschüler ans Pferd und aufs Pferd zu bringen. Es geht natürlich um den Spaß mit einem großen Tier. Das macht er, das macht sein Team sehr gut. Die Reiterpension ist auch in diesem Sommer wieder fast ausgebucht.

Der Ansatz, den Sie dafür wahrscheinlich erwarten, ist ein technischer: Ein Pferd ist in einem Reitstil ausgebildet – Englisch, Western o.ä. –, d.h. es kennt eine Reihe von Kommandos, und der Reitlehrer bringt dem Reitschüler diese Kommandos bei. Eins nach dem anderen. In einer didaktisch klugen Weise.

So etwas gibt es bei Wolfgang Marlie auch. Wenn man dringend möchte. Doch seine Philosophie ist eigentlich eine andere. Wolfgang Marlie ist ein Mann des Grundsätzlichen. Ihm geht es nicht einfach darum, Techniken zu vermitteln, sondern auch und vor allem das Warum dahinter. Es geht ihm um den prinzipiellen Umgang mit Pferden.

Das drückt sich in den Gesprächen zwischen ihm und seinen Reitschülern aus. Darin geht es nicht nur darum, wie zum Beispiel ein Signal besser gegeben werden könnte – sondern immer wieder steht die Frage im Raum, warum denn das Pferd überhaupt auf das Signal reagieren sollte?

Wolfang Marlie lehrt zu einem Gutteil also auf der Meta-Ebene. Für ihn gibt es kein gutes Reiten ohne eine gute Beziehung zwischen Mensch und Pferd. Für ihn gibt es keine verlässliche Verständigung zwischen Mensch und Pferd, wenn sie nicht immer wieder abgeklopft, aufgebaut und gefestigt wird. Ihm reicht es nicht, wenn der Mensch scheinbar Techniken beherrscht – eine Sprache bzw. den Hilfsmitteleinsatz. Ohne Prinzipienverständnis und die rechte Haltung ist ihm das hohl. Es mögen sich für den Moment ansehnliche Leistungen dadurch herstellen lassen, doch ob darunter ein nachhaltiges Verhältnis existiert und auch das Tier Freude hat, ist nicht ablesbar.

Sein Unterricht ist daher eine Lehre in kleinen Schritten. Man sollte viel Zeit mitbringen, wenn man sich auf Wolfgang Marlies verständnisvollen wie verständnisorientierten Unterricht einlässt. Der Wechsel zwischen konkretem Tun, der Anwendung von Techniken, und der Reflexion, der Meta-Ebene, dem Lernen lernen und auch dem Lehren lernen… das kostet Zeit und Ausdauer.

Doch der Lohn der Mühe ist ein ganz anderes Verhältnis zwischen Mensch und Pferd. Tiefer, befriedigender, verlässlicher, ruhiger – und damit auch sicherer.

Wo ist der Bezug zur Softwareentwicklung?

Ich denke, wir sollten an die Softwareentwicklung auch so herangehen. Natürlich ist die ganz anders – oder doch nicht? Dort ein Tier, hier eine Maschine. Das ist ein unübersehbarer Unterschied. Aber: dort ist Kreativität und Blick fürs Detail gefragt, hier ist ebenfalls Kreativität und Blick fürs Detail gefragt. Problemlösungen müssen hüben wie drüben gefunden werden. Nachhaltigkeit ist dort wie hier das Ziel. “Störrisch” stellen sich Tier wie Plattform an.

Und genau deshalb sind die Prinzipien so wichtig. Kurzsichtig lässt sich mit Gewalt viel erzwingen. Gerte und Sporen können ein Pferd in die Spur bringen. Und Zeitdruck mit Fokus auf die Funktionalität kann eine Software in die Spur bringen zum baldigen Release. Das geht. Irgendwie. Doch eher früher als später kommt die Retourkutsche: Das Pferd bockt – dann ist mehr Gewalt nötig. Das Vertrauen ist futsch. Die Software stellt sich bockig bei Veränderungen an, Bugreports häufen sich. Das Vertrauen des Kunden ist futsch.

Doch es geht auch anders. Eben mit einem Blick auf die Prinzipien. Warum soll ein Pferd auf ein Signal reagieren? Warum soll eine Software korrekt sein oder sich über Jahre geschmeidig verändern lassen? Weil Reiter bzw. Softwareentwickler es wollen? Oder weil das so in der Natur der Dinge angelegt ist?

Weit gefehlt! Es braucht Verständnis für die dahinter liegenden Prinzipien. Es braucht Zeit und kleine Schritte. Es braucht die ständige Reflexion.

Das hat Wolfgang Marlie erkannt und setzt es schon in der Reitlehrpraxis ein. Das muss die Softwarebranche noch breiter erkennen. Die Clean Code Developer Initiative ist ein Versuch, dafür Verständnis zu wecken und Anleitung für den schrittweisen Einstieg zu geben.

[1] In der Reiterpension Marlie verbringe ich gerade eine Woche Urlaub mit meiner Tochter. Davor war ich mit Stefan Lieser dort während unseres alljährlichen Retreat. Und aufmerksam geworden bin ich auf Wolfgang Marlie durch eine Empfehlung einer anderen Reitlehrerin. Sie sehen, ich bin begeistert, sonst würde ich nicht immer wieder bei den Marlies einkehren. Für mich herrscht dort jedoch eine so angenehme und anregende Lernatmosphäre, dass ich mich gern in die Schülerposition begebe. Ich kann loslassen und selbst lernen. Dadurch tanke ich auf für die Situationen, in denen ich als Trainer gefragt bin. Anregungen für meine Praxis lauern eben an den unwahrscheinlichsten Orten ;-)

Freitag, 20. Juli 2012

Flow-Design contrasted with Object-Oriented Design

In a recent post Carlo Pescio provided his “true” object-oriented solution to a problem. I´d like to take this as an opportunity to contrast it with the Flow-Design approach to software design.

To bring yourself up to speed regarding the problem scenario, please quickly head over to Carlos article. As a teaser just let me show you his diagram to describe the overall situation where a small program is supposed to help:

image

After briefly presenting the problem, Carlo jumps right into drawing class diagrams. Here´s his final solution:

image

Unfortunately I can´t glean from it, how his solution is supposed to function ;-) His presentation of the solution is just a static diagram, i.e. a depiction of some structure. However, software mainly is a dynamic beast. It´s supposed to do work, to process data.

This is, why I prefer to do software design differently. So let me explain how I´d tackle the problem.

Abstract problem depiction

I think it´s prudent to speculate about programming language artifacts as late as possible. Wielding classes is programming, is rolling in the dirt of the concrete. Designing, on the other hand is approaching a problem first on a higher level, leaving out details – in order to move forward more quickly and to not fall into the trap of premature optimization.

Yes, in the end all lofty design needs to be attached to nitty-gritty code. But why limit ourselves in such a way right from the start?

Also just a drawing, Carlo´s problem depiction is very concrete. I find it hard to jump to any conclusion from that, like which classes there should be. So I like to first draw the system to design (STD) in a more abstract manner. Here´s my system-environment diagram for the sump problem domain:

image

As you can see, I introduced a user role: the operator. Carlo did not talk about it, but I think it´s necessary to have at least one user in the picture. Otherwise it´s not clear why there is a STD at all. Someone has to benefit from it, need it for some purpose. Maybe there should be even more users, like the personnel of a plant who depend on the alarm to sound? But I leave them to the imagination of the reader, to not overcrowd the picture ;-)

The operator is not the only relevant “entity” in the environment of the system. There are sensors and actuators the system has to deal with. I call them resources. Whereas a user role depends on the STD, the STD depends on resources. That´s why the lollypop line ending points away from the STD.

Wrapping the environment

Once I identified the basic dependency relationships, I like to remind me that each should be encapsulated in some way. The innards of the STD should not depend directly on the environment, or to be more precise: on infrastructure APIs to communicate with the environment. This would make the system hard to test.

So I put small symbols in my drawing representing user roles and resources as mere aspects of the solution. Aspect to me means “a set of properties that can change independently of others”.

image

And even though you might not be able to imagine the API of the pump might ever change… there is at least one other kind of pump other than the real pump I want the system to be able to communicate with: a mock-up pump.

When testing the most important parts of the STD, I don´t want to be forced to always connect them to a real pump or any other user role/resource. So there needs to be a way to replace any environmental “entity” with a mock-up. This can be readily accomplished by encapsulating all environmental dependencies in some way.

The rectangles and triangles show me, what I need to do: define an interface for each user role/resource, which then can be implemented by a real API wrapper as well as a mock-up. (If you like to use an abstract class instead, you´re welcome to do so.)

Here are the interfaces for sensors a to e as well as for the pump and the alarm:

image

Yes, I think only two interfaces are required. All actuators behave the same: the pump needs to be started and stopped, the alarm needs to be started and stopped. And all sensors deliver their current value when asked. That´s the simplest wrapping I can come up with. And that´s an important point for me here: environmental entities should be wrapped as thinly as possible. This is to make it most easy to implement mock-ups and also to make testing usage of the environment APIs as easy as possible.

Carlo differentiates between digital and analog sensors – which nevertheless look the same on the interface level – and then further refines them into gas level sensors and level sensors. I would not have done so – at least not at this point, I guess –, but it´s ok with me. What´s important is that these refinements use composition over inheritance:

image

Each threshold sensor instance has its own ISensor instance assigned to it – probably by injection upon construction. It´s configured with an appropriate min/max value and the wrapper around the physical sensor:

var a_sensor = new ThresholdSensor(…, new ASensor());

Other than Carlo my classes would be more concrete the closer they are to the iron: I´d go for a ASensor, BSensor etc. classes implementing the simplest interface (ISensor). That way the least mount of code would be in there, i.e. testing would be as simple as can be.

Carlo on the other hand differentiates on a pretty high level of abstraction: a COSensor is a ThresholdGasSensor is a GasSensor [1]. I don´t get, why I should do that – at least not in light of the given requirements. They tell me, there are different sensors. That´s obvious even from Carlo´s first diagram. So what I can speculate about is, whether those different sensors are talked to using the same or different APIs. From that I would derive whether to implement the ISensor interface in a more general manner (e.g. GasSensor) or very specifically for each sensor type (e.g. ASensor etc.).

Beyond that, though, I don’t see there is a difference between sensors. Even the ThresholdSensor class is a convenience class ;-) It makes the common sensor interaction more specific, it introduces a sensor abstraction to gloss over differences. So I´d say, on this level of abstraction all the different sensors are the same. That´s the whole purpose of this class. One logic to rule all specific sensor API wrappers of a certain kind.

Architectural assumptions

Architecture to me is design with regard to non-functional requirements. After getting a view from 30,000 ft on the problem with the system-environment diagram, some thoughts on architecture might be in order. So what are non-functional requirements of Carlo´s sump scenario? And how do they influence structuring the system?

Well, as it seems, nothing much relevant to architecture is imparted by the requirements description. Performance, scalability, usability, security, robustness… no information on these and many other aspects. No details on the sensors or pump or alarm.

So I´m making two aspects up to become a bit more concrete. This is necessary to actually move forward. System structure is a solution to a concrete problem. That means, as long as the problem is not very concrete there is not really a right or wrong structure. Anything goes.

The assumptions I´m going to make are:

  • The STD is supposed to run as a service on some computer attached to the sensors. Once the computer is switched on the STD will start doing its work. It will monitor the sump, start/stop the pump as necessary, and issue an alarm in an emergency situation.
  • Polling the sensors periodically is enough to deal with changes in gas concentrations and water level. Whether that is every 100 msec or every 60 sec is not that important, I think – as long as processing the data does not take longer than the polling interval.
  • Sensor and actuator APIs can actually be wrapped as to conform to the resource interfaces described above. I explicitly neglect any configuration or startup/shutdown ceremony.
  • Actuators are wrapped in an idempotent way: switching on a pump that´s already running does not make a difference.

This is how I imagine the setup:

image

Modeling the solution

Now for the fun part. How should the whole system work? Carlo´s talking about this, but when I look at his blog article I don´t see it. The result of all his work is, well, just a structural diagram. All explanations about functionality are lost.

I deem it no virtue to be able to “reverse engineer” a class diagram to get an idea how things are working. If that´s all you have, a class diagram, well, then you have to do it. But my approach to software design and programming is, to avoid this kind of extra work. Develop software so it can be understood and changed easily. That requires to make functionality, i.e. how things play together, a first class citizen of the design.

This is, why I view software as a set of interactions with its environment. Yes, I´m modelling functionality using interactions or behaviors, not objects. At least objects as “bags of behaviors” are not where I start. My reason is simple: it´s notoriously hard to find such objects in the requirements. Except… yes, except for requirements dealing with real world things. In so far I´d say Carlo´s cheated a bit ;-) when he chose his scenario to demonstrate his object-oriented approach. The scenario makes is particularly easy to arrive at a class decomposition of the problem. For many, many developers, though, it´s not that easy because they deal with totally different stuff.

However, required behavior is always present. Software as a whole is always supposed to do something. So why not start from there? Start with one “thing” a software should upon request from a user role. Whatever has to be done thus is always triggered by some event in the environment. For the sample scenario that´s trivial: the operator starts the sump monitoring service by switching on the computer.

image

About this picture I can talk with the customer or a user. It´s dead simple. I can ask them, if that´s all to the interaction “Start program” – on this level of abstraction. The program is started with no further information. From then on it just runs…

If everyone agrees I can drill down. What does “Monitor the sump” mean?

image

It means, this should be done periodically done. That´s a non-functional requirement. So it should show up in my model somewhere.

What has to be done periodically? Reading the sensors aka polling – and then acting on the data read from the sensors. That means the pump has to be switched on/off as necessary. And in case of an emergency the alarm has to be switched on.

I guess I could talk with a user on this level of abstraction, too. He could tell me, if I understood the problem domain correctly. And if´d be interested we could drill down further:

image

Reading the sensors could be done in parallel. They are independent of each other. And once all the readings are in, they can be packed up in a SensorData structure for consumption by the “domain logic”.

Note the drums next to the process steps. They signify a dependency. The process step depends on a resource, it accesses the resource in some way.

Ah, by the way: did you notice how I “stepped into” process steps. The previous diagram refines the process step “Read sensors” of the diagram above it. And that diagram refines the process step “Monitor the sump” of one diagram before. So what I´m doing here is truly modeling on different levels of abstractions.

No, I´m not using the L-word here. I don´t care much about layers. I never draw a layer diagram to start a software design. It simply does not help me in any way. It´s either trivial to state which layers there are – or limits my freedom in designing a solution.

Now comes the interesting part. How does the monitoring software actually do anything with the sensor data?

There are two “things” in the environment to control: the pump and the alarm.

The pump has to be switched on/off depending on the water level. However, if the methane sensor signals a certain value, the pump needs to be switched off regardless of the water level[2]. Both situations are assessed separately. The combined result then is evaluated to finally decide whether the pump needs to be switched on/off [3].

image

Whereas the “Read *” process steps do not add anything to the basic interface methods of the sensors, “Switch pump” contains some logic on top of calling the pump interface. But that does not hurt. The functional unit for “Switch pumpt” is easy to test due to IoC. It just knows an actuator interface and thus can be made to work on a mock-up during testing.

And now for the final refinement:

image

Straightforward, isn´t it? Assessing the gas readings is pure “domain logic”. Does is matter it also gets water level sensor data? No, I don´t think so. That´s trivial excess information. To separate sensor data to deliver it in a more fine grained manner, would not add much at this point. It´s an optimization, if need be.

Abstracting classes from the model

The modeling diagrams show how the solution is going to work. I´d say they can be understood pretty much even by a user, not to speak of a developer. To me they make clear where and when certain decisions are made. And they do so on many levels of abstraction, so I can explain/learn about the system at my pace/according to my needs. No reverse-engineering, no code archaeology necessary.

And the best part is: what you see above is the code to be executed. Almost. And of course on just a high level of abstraction. But nevertheless it´s code.

But how can such bubbles be executed? Well, I´m gonna show that in a future post, I guess :-) For now I´d like to focus on just what Carlo has provided: the model.

To live up to that, though, I need to do one more step. I need to show you the classes my design approach leads to.

Please note: For me classes don´t stand a the beginning of the design process. Rather they are the closing bracket matching the opening bracket of the system-environment diagram. Some classes might be easily gleaned from the requirements. Well, if that´s the case, write them down. Great – but be careful. They´re still lacking justification, until you assigned them functionality. (With the exception of pure data classes.)

That´s why I leave classes out as long as possible. They are abstractions, they are grouping constructs. They bundle “stuff” that belongs closes together than other stuff. So why should I start think about classes before I know what my “stuff” is?

The “stuff” of software is functionality. Or in more technical terms it´s functions, procedures, that means methods. That´s why I start by compiling the methods I need to deliver certain functionality. I do that top-down. And I do it in a cross-cutting way.

So what I´ve presented you so far is an assembly of methods. Each ellipsis can be translated into a method, sometimes a function, sometimes a procedure.

But here´s the trick: only leafs of the tree the above diagrams are spanning need to become methods; the are the actual operations of the software system. Any darkly colored ellipsis stands for such a leaf. The intermediate nodes of the flow network need not be encoded in any 3GL programming language. Their sole purpose is integration.

Here´s an overview of the whole model with operations colored according to class:

image

As you can see, I cam up with six different classes as work horses for the software system. That is, four of them are in addition to the basic wrapper classes for resources.

image

Now let me direct your attention to what´s missing: dependencies.

See how the classes each stand pretty much on their own? In Carlo´s class diagram there are so many lines of different kinds going in all directions. Some signify abstractions, some composition. It´s – sorry to say, Carlo – a bowl of spaghetti.

I dare to say that on the other hand the classes I came up with are not less focused in their responsibilities – but less entangled and thus much easier to understand. And there is no controller class either – which was the whole purpose of Carlo´s exercise ;-) Each method in the classes will be small, i.e. easy to test, easy to understand.

The classes are so little connected, I hardly need a class diagram at all. Why should it tell me anyway except for, well, the structure of data? But since the problem scenario hasn´t to do much with data, there is no need for a class diagram. I´m perfectly fine with the above data flow diagram annotated maybe with class names to make it a bit easier to find the methods in the code base.

Inevitable extensions

Two extensions I´ll leave open for now. This article has already gotten quite long.

  • Logging
  • Pump failure detection

I´d say, as long as it´s easy to add these requirements later on, my design could be considered at least reasonable. We´ll see…

Critique

One argument I can foresee: “What you do, Ralf, is just functional decomposition like in the 1970s. And we know that´s not gonna work.”

Well, yes, that´s a kind of functional decomposition. And I don´t see what´s wrong with that. Since software is about actions, process, behavior, “functions” are what we should be looking for. That´s the very stuff, software is build out of.

That said, I´m not opposed to object-oriented concepts and languages features. Right to the contrary. That´s all nice and well – where it´s appropriate.

As you can see I make use of interfaces. And I like to encapsulate data. And of course what belongs together should go together into a class. Or a component. Or an assembly. Or a process.

But I´m not on the outlook for small virtual machines. Encapsulation of details (state, logic) is great. But it´s an optimization. Trying to start software design with classes thus to me more or less is premature optimization.

If you´re serious about the term “class” then don´t just understand it as a schema. Also view it as an abstraction of functionality, i.e. a name for a group of methods. And like any other class of stuff software classes then are the result of collecting stuff first. Then classifying it. That´s what Linné did. That´s what we as software designers should do.

Some classes might be obvious. But more classes are not, I´d say. They need to be abstracted from functionality. That´s what I´m doing. But because of this approach I´m not doing plain procedural programming.

There´s also another telling trait of my approach: data flow. Procedural programming never used data flows. Flow-charts or structograms relied on global data, not data flowing from step to step. But that´s what I favor. It keeps dependencies local. And it makes it more obvious what´s happening.

Summary

So much for my plea for Flow-Design :-)

This was fun. I finally was able to contrast my approach with a “true” OO approach. The result is looking different in many regards – but at the core there is some overlap. Of course. Carlo and I agree on the need to wrap resources behind interfaces.

However, we view the software world structured differently. He starts with a vision of small virtual machines (objects) whereas I view software as a bunch of processes (integration) made up of smaller and smaller steps (operations).

Now it´s your turn to compare and assess the two approaches. Looking forward to some discussion – if you like.

Footnotes

[1] I´m aware Carlo also ponders the possibility to have just three instances of ThresholdGasSensor. But he seems to favor more specific classes. That´s at least what he chose to depict and thus make his final solution more complicate.

[2] To me it seems Carlo´s design not really caters to this requirement. For him a gas sensor signals either a critical state or not. I have followed him in this so far. But if I think more closely about it, the critical level for an alarm and for switching off the pump might be different. The GasSensor interface might be too limited. But the requirements are not precise on this. So I´ll leave it at that.

Dienstag, 17. Juli 2012

Smarter Entwurf mit smartem Tool

Software mit Flow-Design zu entwerfen, finde ich smart. Die Ergebnisse sind leicht verständliche, leicht in Code zu übersetzen und evolvierbar. Papier und Bleistift reichen eigentlich aus. Naja, eine Digitalkamera darf es dann auch noch sein, um die Entwürfe ins Repository legen zu können.

Jetzt waren Stefan Lieser und ich allerdings eine Woche bei einem Kunden zu einer Entwurfssitzung und haben uns von einem Tool begeistern lassen. So ein SMART Board von www.smarttech.com ist echt cool.

Grundlegen technisch gesehen ist ein SMART Board ein virtuelles Whiteboard. Man kann auf dem, was ein Beamer projiziert rummalen. Das gibt es in verschiedenen Ausführungen am Markt.

Im Detail aber macht eben ein SMART Board den Unterschied zum Whiteboard. Man kann nämlich nicht nur auf einem virtuellen Blatt herummalen, sondern auf allem, was projiziert wird. Der Beamer an der Decke sorgt dabei dafür, dass man sich nicht im Licht steht:

image

Hier zum Beispiel in einem Visual Studio Projekt oder in einem PDF-Anforderungsdokument:

image   image

Was immer in der Weise annotiert wird, kann zu einem Dokument ähnlich einer PPT-Präsentation ganz leicht zusammengefasst werden. So ergibt sich ein lückenloses Protokoll des Arbeitsfortschritts über Medien hinweg: vom weißen virtuellen Arbeitsblatt über Textdokumente, Spreadsheets bis zur Entwicklungsumgebung oder schließlich der laufenden Anwendung.

Ja, genau, Arbeitsergebnisse mit dem SMART Board vorgeführt, können sofort vom Kunden annotiert werden. Das Abnahmeprotokoll muss dann nicht lange “übersetzt” und getippt werden, sondern besteht aus Schnappschüssen, die “am Objekt” zeigen, was wie anders sein sollte.

Am Ende der Entwurfssitzung haben wir dann die SMART Board “Foliensammlung” als PDF gespeichert und ebenfalls ins Repository getan:

image

So lag sie jedem Entwickler auch bei der verteilten und asynchronen Entwicklung vor. Und niemand musste Zusatzaufwand treiben für ein Protokoll.

Zum Schluss noch ein besonderes Schmankerl: Was man da so malt am SMART Board ist Vektorgrafik. D.h. die Bildelemente lassen sich gezielt selektieren und verändern. Damit sind auch bei handschriftlichen Notizen sehr komfortable Umgestaltungen möglich.

Für Stefan und mich ist das Fazit: Softwareentwurf ohne SMART Board ist eigentlich nicht mehr zeitgemäß. Ad hoc, flexibel, informell, schnell, medienübergreifend – so geht das mit dem SMART Board. Wir wollen jetzt auch eins…

Donnerstag, 12. Juli 2012

Machbare Veränderungen - Daneben statt rein

imageDas Brownfield ist überall. Teams ersticken in Support, strategische Entwicklung findet nur zufällig statt, Kunden warten lange auf zugesagte Änderungen, das Backlog enthält Tausende Einträge aus mehreren Jahren. Alles schon gesehen. Und nicht nur einmal.

Wenn dann irgendwann das Schmerzempfinden des Teams diese Situation als wenig nachhaltig signalisiert, ist guter Rat teuer.

Kann umfangreiches Refactoring aber nicht die Situation retten? Kaum. Denn wo ist der Kunde – intern oder extern –, der es aushält, dass über diese Refactoring-Maßnahmen lange kein äußerlich sichtbarer Nutzen produziert wird.

Oder vielleicht neu schreiben? Ja! Das wäre cool. Macht auch mehr Spaß, als am alten Code rumzumokeln. VB6 geht auch beim schönsten Refactoring nicht weg. Am besten während der Neuentwicklung das Brownfield mit dem kleinstmöglichen Aufwand am Leben halten. Und irgendwann wir umgeschaltet auf das strahlende Neue. Kaum. Woher sollen denn die Ressourcen kommen, die das Neue zügig vorantreiben, wenn am Alten auch noch gebastelt werden soll? Und wie ist es mit einem Termin für die Neuentwicklung?

Möglichst schnell? Dann ist es noch schwieriger mit den Ressourcen. Vor allem haben Entwickler, die Jahre lang im Korsett eines Brownfields gearbeitet haben, wenig Übung darin, ein Greenfield zu bestellen, so dass daraus nicht bald wieder ein neues Brownfield wird.

Oder darf es ruhig dauern, bis die Neuentwicklung fertig ist? Es soll ja auch was richtig Gutes rauskommen? Dann fehlt die Motivation zu häufigem Feedback. Dann ist das Risiko groß, sich in Forschung und Frameworks zu verlieren. Eine never ending story…

Nein, ich halte beide Wege inzwischen für falsch. Aus dem Brownfield kommt man durch keinen Refactoring-Gewaltmarsch heraus und auch nicht durch den großen Wurf einer kompletten Neuentwicklung.

Die Lösung liegt vielmehr darin, an das Bestehende anzubauen. Wie oben in dem Bild. Weder wurde die Villa entkernt, noch wurde sie abgerissen, um etwas Neues zu schaffen. Vielmehr wurde sie in Ihrem Wert erhalten und um etwas Neues erweitert. Das Neue ergänzt das Alte. Das Neue ersetzt in Teilen das Alte. Vielleicht doppelt es das Alte übergangsweise auch, um es schließlich abzulösen?

Ja, so sehe ich das bei der Softwareentwicklung auch.

Das Brownfield muss nicht refaktorisiert werden, um mit ihm und in ihm weitere Jahre erfolgreich zu sein. Vielmehr ist im Brownfield ein Teil zu identifizieren, der freigestellt werden kann. Nur dieser Teil wird dann neu entwickelt. Das ist überschaubar. Während der Neuentwicklung, ist die alte Version der Funktionalität im Brownfield erhalten. Aber irgendwann wird sie dort abgeklemmt, um von der Neuenentwicklung übenommen zu werden.

image

Die Neuentwicklung kann mit dem Brownfield über eine gemeinsame Datenbank verbunden sein. Aber darüber sollte man gut nachdenken. Besser ist es, hier wird die Chance genutzt, um auch darin aufzuräumen. Also eine neue Datenbank aufsetzen und mit der bisherigen Synchronisieren.

image

Nur so geht es, glaube ich. Masterpläne, die alles auf einmal richten, sei es mit Refactoring oder kompletter Neuentwicklung, sind Geldgräber. Es kommt nichts raus. Oder es dauert zu lange, als dass es die Kunden zufriedener machen würde.

Besser ist es, Sie stellen “agile Schnellbote” neben Ihren “behäbigen Schlachtschiffen”. So können Sie schrittweise Ihr Brownfield aushöhlen. Und irgendwann gibt es nur noch einen Schwarm von “Schnellboten”, die unkompliziert separat evolvierbar sind.

image

So funktioniert das auch mit Städten. Die werden nicht platt gemacht – außer in Kriegen. Sondern die wachsen und verändern sich Haus für Haus. Der “Schwarm an Häusern” teilt sich natürlich Infrastruktur. Das können die vielen “Software-Schnellbote” auch. Ansonsten sind sie jedoch unabhängig. Jedes für sich kann verändert oder abgerissen werden. Kein Masterplan ist nötig. Kein “Wenn wir mal Zeit haben…”. Deshalb: Strukturieren Sie Ihre Software genauso. Versuchen Sie weniger, darin etwas großartig zu verändern. Stattdessen stellen Sie lieber die Neuerung daneben – und lösen Sie auch so Altes durch Neues ab.

Dienstag, 10. Juli 2012

Was andere schon richtig machen - Reviews

2012-07-04 09.32.07Das ist Galina Knoll. Sie ist Hausdame im Hansa Apart Hotel in Regensburg [1]. Von ihr können wir als Softwareentwickler etwas lernen.

Als Hausdame ist eine Ihrer Aufgaben, die Reinigung der Zimmer zu überprüfen. Sie hat einen Plan, welche Zimmer zu reinigen sind – das hängt ja davon ab, wann welche Gäste abreisen. Den Plan spricht Sie mit den Zimmermädchen ab, die die Zimmer herrichten. Und am Ende überprüft Sie, ob die Zimmer den gewünschten Zustand haben. Manche müssen prick für einen neuen Gast sein; andere müssen “nur” für eine weitere Nacht desselben Gastes wieder frisch sein.

Natürlich geht bei Dutzenden oder gar Hunderten Zimmern immer etwas schief. Eine Hausdame ist deshalb dafür zuständig, Qualitätsmängel einer Behebung zuzuführen. Manches muss nochmal vom Zimmermädchen nachgebessert werden. Für anderes ist der Hausmeister zu informieren.

In die Sprache der Softwareentwicklung übersetzt bedeutet das: Galina Knoll ist für den Review der Arbeitsergebnisse zuständig.

Hotels haben schon lange gelernt, dass die “Aufräumarbeiten” der Zimmermädchen nicht allein genügen, um die Qualität herzustellen, die der gute Ruf eines Hotels für seinen Erhalt braucht. Es kommt zu sehr darauf an, dass in den Zimmern alles stimmt, als dass man sich dort Nachlässigkeiten erlauben dürfte. “In Produktion gehen” Zimmer also nur nach einem Review durch die Hausdame.

Und wie ist es bei der Softwareentwicklung? Kommt es da nicht für den guten Ruf des Entwicklungsteams bzw. des Softwarehauses darauf an, dass die Qualität des Codes stimmt? Ich meine, schon. Er ist das Aushängeschild – auch visuell/haptisch durch die Usability, aber auch durch seine Stabilität. Fehler jeder Art turnen den Nutzer genauso ab, wie den Hotelgast die Fußnägelreste der Vorgängers in der Dusche oder Spinnweben über dem Bett.

Warum hat dann aber die Softwarebranche noch nicht dasselbe gelernt wie die Hotelbranche? Warum sind Reviews nicht etabliert in jedem Team? Warum lässt die eine Branche Zimmermädchen bei vergleichsweise einfachen arbeiten nicht ohne Endkontrolle – und die andere Branche überlässt die Hersteller ungleich komplizierterer Ergebnisse “ihr Zeug” einfach an den Kunden geben?

Es ist nicht zu verstehen. Und bitte: Man mögen mir den Einwurf “Keine Zeit!” ersparen. Den könnte die Hotelbranche auch vorbringen. Es wäre doch alles einfacher/billiger, wenn die Reinigung schneller ginge weil ohne Review. Trotzdem verzichtet man nicht auf die visuelle und persönliche Kontrolle. Der Grund: Man hat verstanden, dass schlechte Qualität früher oder später den Geldfluss verringert. Entweder direkt, weil weniger Gäste buchen – dann muss man die Preise senken und dann weiter an Kosten Sparen. Eine Negativspirale setzt ein, die niemanden zufrieden macht. Oder indirekt, weil Aufwand durch Nachbesserung entsteht, wenn Gäste sich beschweren. Der zieht wertvolle Kräfte zur Unzeit von Wichtigerem ab.

Ich würde also sagen: Wir können etwas von der Hotelbranche lernen. Und das nächste Mal, wenn Sie in einem Hotel sind, freuen Sie sich bewusst über die Abwesenheit von Mängeln. Alles ist sauber und frisch.

Wäre das nicht auch wünschenswert für die Software, die Sie ausliefern?

Mein Dank gilt Galina Knoll und ihren Kolleginnen und Kollegen in den vielen Hotels, in denen ich jährlich einige Zeit verbringe.

[1] Im Hansa Apart Hotel bin ich gerade für ein paar Tage während eines Kundentermins. Da ist mir Galina Knoll morgens mit ihrem Notizblock und dem großem Schlüsselbund aufgefallen. Und es ist mir bewusst geworden, was wir von ihrer Rolle lernen können.

Donnerstag, 5. Juli 2012

Flow Runtime Meets Event-Based Components

Dass die Flow Runtime ein Ersatz für Event-Based Components sein soll, hat nicht jedem Freund des Flow-Design geschmeckt. Nicht alle sind deshalb mit fliegenden Fahnen zu NPantaRhei übergelaufen.
Ok, ok, kann ich verstehen. Aber jetzt ist Schluss :-) Jetzt gehen Event-Based Components (EBC) nämlich auch mit der Flow Runtime. EBC werden von der Runtime einfach in Operationen “übersetzt”. Und das geht so:

class Rechenwerk
{
    public void Teilen(Tuple<int,int> input)
    {
        if (input.Item2 == 0)
            DivisionDurchNull(input);
        else
            Resultat(input.Item1/input.Item2);
    }
 
    public event Action<int> Resultat;
    public event Action<Tuple<int,int>> DivisionDurchNull;
}

Eine Instanz EBC-Klasse wird dann einfach bei der Konfiguration reingereicht:
var config = new FlowRuntimeConfiguration()
        …
        .AddEventBasedComponent("rechenwerk", new Rechenwerk());

Die Runtime analysiert die Klasse und bietet dann alle Methoden mit der Signatur
  • Action
  • Action<T>
als Input-Port an. Der Methodenname ist der Portname. In diesem Fall wäre es nur Teilen.

Alle öffentlichen Events mit ebensolcher Signatur erkennt die Runtime als Output-Ports. Der Event-Name ist der Portname.

Im Flow müssen dann die Ports explizit angegeben werden.

var config = new FlowRuntimeConfiguration()
                .AddStreamsFrom(@"
                                 /
                                 .in, rechenwerk.teilen                                                rechenwerk.resultat, .result
                                 rechenwerk.divisionDurchNull, .error
                                 ")…

image

Bei Func/Action-Operationen gibt es keine Portnamen, weil sie durch den Verwendungsort der Operationen automatisch unterschieden werden kann zwischen Input und Output. EBC sind also ausführlicher. Aber das ist ja auch Sinn der Aktion. Auf EBC werden Sie zurückgreifen, wenn Ihre Operationen mehrere Input- und/oder Output-Ports haben.

Ich hoffe, damit ist es nun für alle attraktiv, sich mit der Flow Runtime zu beschäftigen. Selbst wer ganz auf EBC eingeschossen ist, kann jetzt davon profitieren, dass Flows für die Runtime mit einem Visualizer definiert und sogar aus Assemblies wieder ausgelesen werden können. Oder er kann ganz einfach die Verarbeitung in einer EBC-Instanz in den Hintergrund legen. Oder sie kann Exceptions in einer EBC-Instanz mit einer Causality abfangen – selbst wenn es auf einem Hintergrund-Thread gekracht hat.

Enjoy EBC at the next level!