Thursday, June 24, 2010

Notes on Software Design, Chapter 7: a better Forcefield Diagram

In my previous post in the NOSD series, I mentioned how an improved forcefield diagram was needed to model the kind of reasoning I'm trying to bring in software design. I also discussed the artifact-run/time dualism, and how many concepts in language design were born out of the fundamental need to balance conflicting forces between these two worlds. I also mentioned the role of some patterns in resolving the same kind of conflict.

Here I'll show you a practical example, introducing the improved forcefield notation as we go. It's quite simple, and as usual, the reasoning is more important than the drawing. I'll use new colors and shapes, but it's all very informal, the notation is not cast in stone, and it will probably evolve and change over time.

A common problem
You have two classes (Class1, Class2); as we learnt in Chapter 6, that usually means you have two artifacts, and right now I feel like blue is a good color for artifacts, so I'll color them in blue.

Now, those classes have some commonality in behavior; for instance, they both represent a geometrical object, and can provide you with a bounding box.
Behavior is a run-time concept, and I'll color that information in pink.

Commonality in behavior is an attractive force; I haven't talked about this yet, but trust me : ), or just rely on your intuition that "things that do similar things are close to each other".

Commonality in behavior also attracts a natural desire in the artifact space: polymorphic/uniform access to such behavior. While writing calling code, I'd like to ask for a bounding box in the same way, perhaps polymorphically through a base class / interface. That would make my client (partially) unaware of the specific classes.

Unfortunately, Class1 and Class2 have been written with different conventions. They don't share a base class; they don't use the same naming for functions; they may not even use the same types for parameters. Different conventions are an artifact issue, so I'll color this in blue again. Of course, different conventions are keeping Class1 and Class2 apart, and actively rejecting polymorphic / uniform access. So here is the forcefield, representing our problem:



Note that there is nothing here about a solution. At this stage, the forcefield is a representation of the problem. Still, we have a conflict between forces, and somehow we have to deal with it. What if we don't? I'll keep that as last.

Enter decisions
A missing concept in my previous attempts at modeling the forcefield was the very important notion of decision. Although I'm trying to keep concepts to a bare minimum, the Decision Space is an important piece of the puzzle, and there can't be a Decision Space without Decisions. I'm using a yellow hexagon to represent a decision.

So, how can we deal with those conflicting forces? A simple, technically sound decision is to refactor Class1 and Class2 to a common base class (or interface, or a hierarchy of both). That decision has a strong impact on "Different Conventions", effectively removing it from the forcefield, including the rejection lines. I think the diagram speaks for itself:



So, decisions can alter the forcefield, for better or worse. Still, we may choose to keep the artifacts unchanged. Perhaps Class1 and Class2 come from third-party libraries, or perhaps they're shared with a lot of existing code, and refactoring may impact that code as well (remember Mass and Inertia). Again, it's useful to represent this decision explicitly, although it's just an intermediate step. I colored "Different Conventions" in green to say that we deliberately decided to keep it inside the forcefield.



Patterns
Design patterns are now mainstream, with dozens of books and hundreds, if not thousands, of papers describing the problem / context / solution triad.
Now, the solution is usually represented using a UML diagram and/or some source code. Problem and context are described using text, or an example in UML/code. That's because we don't (didn't :-) have any proper way to describe a problem (forcefield) and context (mostly, pre-made decisions).
Still, look at the picture above once again: that's (of course :-) the problem/context setting for a well-known pattern: adapter. So let's look at the adapter in action, or how using adapter will impact the forcefield:



Adapter "simply" breaks the rejection between Different Conventions and Polymorphic / Uniform Access, therefore allowing client code to ignore the specific interface of Class1 and Class2. It is very interesting to observe what the forcefield is telling us: we didn't completely remove conflict. There is still an attraction/rejection between Class1 and Class2. In this sense, Adapter is less effective than refactoring (which, however, requires us to change the artifacts).
That conflict will emerge over time; for instance, adding common functionality will take more time, possibly some duplication of code, etc. This kind of "consequence" is not very well documented in the GoF book.

Note: there is no redundancy with code here: we're talking about the problem space and the decision space. Contrast this with the usual redundancy between a UML diagram and code (with pros and cons, as usual). Also, isn't this diagram much better at communicating design problems, decisions, and impact than the largely ignored design rationale tools and notations?

What else?
There is also a different decision we can make; it's a particularly bad decision, therefore it's also very popular :-) wherever code quality is easily ignored. We can just forgo uniform access, and have clients deal with a non-uniform interface (through if, switch/case, whatever). This is what I meant by "not dealing with conflict" earlier. I called that decision "Tangled Clients" for reasons that will become clear in a future post.



Time out
Last time I said I would provide some examples of conflicting forces in the non-software world. I'll have to cut this post short, because the forcefield diagram I've come up with would take too much to explain. But I'll offer a few pointers for those of you with some time to spare:

- Very simple: the adapter is extremely frequent in the real world as well, as the well-known socket adapter. The forcefield is remarkably similar, but finding the exact translation of every concept is not necessarily trivial. Try this out :-).

- Harder, some engineering knowledge is required. Rotating pumps may leak (why? hint: some empty space is needed if you want something to rotate freely :-). Old pumps just used a seal, which wasn't really good at preventing leaks. At some point (I think around 1940) the end face mechanical seal has been adopted as a better seal for rotating pumps. However, the fluid can still leak, which ain't that good in a number of cases. An interesting solution here is the magnetic drive pump (look it up, guys :-). Draw the forcefield for the problem, and represent how using a magnetic field to transmit movement can compensate otherwise conflicting forces. By the way, this is the example I was thinking about when I wrote my previous post.

- Manufacturing is actually full of great examples of conflicting forces and different approaches to compensate or overcome conflict. Think about thermal grease, just to give a starting point. The list is endless. Trying to model some forcefield in detail is a fascinating exercise.

- If you want to stay on the software side, here is an interesting one. Take some programming language feature (for instance, if you use .NET, you may consider partial classes or attributes; if you use Java, annotations) and identify which tension between the run-time world and the artifact world they're meant to solve. Partial classes are a simple, but interesting exercise: most criticism I've heard about them is stemming from a very partial :-) understanding of the surrounding forcefield, just like the common abuse I've seen (split a large class in two files :-)).

As usual, there is much more to say about compensating forces, the artifact/run-time dual nature of software, and so on, including an unexpected intuition on economy of scale that I got just yesterday while running. See you soon, and drop me a line if you try this stuff out :-)

5 comments:

daniele said...

Dal post precedente sul forcefield diagram, avevo dedotto che le forze repulsive e attrattive di un diagramma individuano alcuni cluster di elementi.
Ciascun cluster è formato da tutti gli elementi legati da forze attrattive e i cluster sono separati dalle forze repulsive.

Il diagramma con solo i cerchi e le forze tra essi rappresenta la descrizione del problema e, se ho ben capito, i conflitti tra le forze dovrebbero risultare evidenti dalla presenza di più cluster.
Ovvero: una soluzione al problema in esame consiste nella scelta di uno solo fra i cluster individuati.

Nel diagramma del tuo esempio, però, inserisci come elmenti anche le due classi Class1 e Class2, e questo fa cadere la mia teoria: come posso scegliere come soluzione un cluster in cui non sono presenti
le due classi?

Quello che mi impedisce di cogliere i conflitti tra forze, credo sia la presenza nel diagramma di elementi concettualmente diversi (artifact, loro proprietà, desideri...) rappresentati con lo stesso simbolo.

Anche i simboli per le forze mi sembra che vengano usati per rappresentare concetti molto diversi: ad esempio, la forza che respinge "Different Conventions" e
"Class1", mi sembra molto diversa da quella che respinge "Different Conventions" e "Polymorphic/Uniform Access". Tra l'altro la vera forza repulsiva sarebbe tra "Class1" e "Class2" (e "Different Conventions" ne sarebbe la causa), più che tra le classi e "Different Conventions".

Alla fine si capisce lo stesso cosa vuoi trasmettere, ma personalmente questa disomogeneità non mi consente di individuare così facilmente i conflitti tra le forze in gioco e le soluzioni al problema.

Carlo.Pescio said...

Rispondo quotando un po' del tuo testo abbreviando per limiti stile anni 80 di blogger (4096 caratteri per commento) che gia' mi portano a dare 2 risposte separate (che roba : ))

Ciascun cluster è formato da tutti gli elementi legati da forze attrattive e i cluster sono separati dalle forze repulsive.
Premesso che essendo una teoria in divenire tutto cio' che dico puo' essere invalidato al post successivo [succedera' :-)], confermo che questa e' l'idea di fondo, o meglio: all'interno di un cluster le forze attrattive sono piu' forti delle repulsive, tra cluster le forze attrattive sono deboli e le forze repulsive piu' forti.

i conflitti tra le forze dovrebbero risultare evidenti dalla presenza di più cluster.
No, i conflitti tra forze sono semplicemente :-) conflitti tra forze :-)), ovvero, tra due nodi ho sia una attrazione che una repulsione.

una soluzione al problema in esame consiste nella scelta di uno solo fra i cluster
No, non piu'. Questo era vero nella versione precedente del diagramma, che mescolava problema e soluzione. Tenendoli separati, il problema ha una sua forma, le decisioni alterano il campo di forza rendendolo [se buone] piu' favorevole, e creando quindi i giusti cluster. Un diagramma, non appena introduciamo le decisioni, diventa una soluzione (o uno step di una soluzione). Non ci sono piu' soluzioni multiple rappresentate sullo stesso diagramma. Questa cosa non scalava bene.

come posso scegliere come soluzione un cluster in cui non sono presenti le due classi?
Vedi sopra: non devi farlo. Ma una soluzione puo' alterare le forze tra c1 e c2.

Quello che mi impedisce di cogliere i conflitti tra forze, credo sia la presenza nel diagramma di elementi concettualmente diversi [...] rappresentati con lo stesso simbolo.
Spero di no. La minimalita' della notazione e' una cosa a cui punto molto. So che dovro' introdurre altri simboli ma lo faro' col contagocce. Spero invece che la difficolta' nasca dai cambiamenti semantici :-) rispetto al precedente forcefield diagram.

Carlo.Pescio said...

la forza che respinge "Different Conventions" e
"Class1", mi sembra molto diversa da quella che respinge "Different Conventions" e "Polymorphic/Uniform Access"

hmmm, no, direi che e' molto simile, ma qui mi rendo conto che non avendo raccontato ancora un sacco di cose non e' immediato fare il salto. E che forse sarebbe stato piu' semplice capire i diagrammi se avessi introdotto esplicitamente le classi client, a costo di somigliare un po' troppo ad un diagramma uml :-). Ci penso su e magari propongo un altro diagramma / set di diagrammi per modellare la stessa situazione.

Tra l'altro la vera forza repulsiva sarebbe tra "Class1" e "Class2" (e "Different Conventions" ne sarebbe la causa)".
sigh : )). Questa cosa e' verissima e la notavo anche io creando il diagramma. Del resto e' una delle ragioni per cui sto raccontando questa teoria incompleta: raccogliere feedback.
Purtroppo ci sono situazioni (come questa) in cui mi servirebbe un concetto di "nodo" da cui escono linee di forza multiple. Questo nodo per ora l'ho sostituito con un nodo "standard" a cui ho dato, di fatto, il nome della forza. E' una cosa su cui devo ancora pensare, ovvero:
- mi serve per forza il concetto di nodo per le linee di forza?
oppure
- e' solo che non ho trovato il nome giusto per quel nodo standard?
Al di la' di questo specifico esempio, non ho ancora preso una vera decisione che abbia anche una sua sensatezza teorica. Andando avanti risolvero'...

questa disomogeneità non mi consente di individuare così facilmente i conflitti tra le forze in gioco
Convertire il normale pensiero progettuale in uno basato solo su attrazioni e repulsioni non e' necessariamente semplice. Non credo che in realta' sia un problema di arricchire la notazione (che non vuole modellare i concetti a cui sei abituato: contenimenti, ereditarieta', chiamate di funzione, ecc). Se hai tempo e voglia, prova a modellare con questo tipo di diagrammi un problema familiare, pensando pero' solo in termini di attrazioni-repulsioni. Ipotizzo che la difficolta' diminuisca con la pratica :-).

daniele said...

Ok, proverò a modellare qualcosa, e poi ti farò sapere.
A proposito: tempo fa avevi parlato di uno stencil per creare i diagrammi con visio. Non è che me lo potresti mandare, per favore?

Carlo.Pescio said...

ho fatto di meglio : ), ho aggiornato la pagina dei tools sul mio sito e aggiunto gli stencil.

nota: nel file ci sono anche alcuni simboli che non ho ancora utilizzato negli esempi del blog e sulla cui necessita' ho ancora qualche dubbio...