In my last post, I noted some of the ways in which I use modeling (mostly UML) to capture and communicate aspects of a design. As I was finishing the post, Simon Brown and I shared the following exchange on Twitter:
Last night I asked an audience of ~40 people who used UML on a regular basis and only 4 hands went up. This is now the norm…
— Simon Brown (@simonbrown) May 16, 2012
…and that’s fine, but how are teams communicating their software designs? (I’m not talking about post-project documentation)
— Simon Brown (@simonbrown) May 16, 2012
@simonbrown I wonder how much of that comes from worrying about getting the UML “right” versus communicating the design?
— Gene Hughson (@GeneHughson) May 16, 2012
@GeneHughson that’s certainly one of the points often raised, and people seem nervous about “bending” the notation
— Simon Brown (@simonbrown) May 16, 2012
I find this bemusing for a number of reasons, not least of which is my somewhat iconoclastic nature. It’s my belief that form follows function; that much is pretty hard to miss. Even more so, I believe that form should never trump function. Diagrams are a means of communication, not an end in themselves. Being afraid to use a communication tool just because you’re afraid of “breaking the rules” is as shortsighted as producing artifacts that are syntactically correct but infeasible in practice. Design artifacts, whether intended as blueprints for work in progress or documentation of the system’s current state, must enhance an understanding of the system. If they fail at that aspect, then any other consideration is moot.
The other side of the coin is that if the artifact serves to communicate effectively, whether it conforms to a particular modeling language or not is irrelevant. I used the diagram on the right (affectionately dubbed “the udder diagram”) a few years back to communicate the strategy of integrating four line of business customer portals with four back-end systems using a messaging platform. It served to illustrate that strategy to both business and technology, across all levels from development teams to channel presidents. Refusing to use it because it wasn’t part of some standard notation would have made no sense at all.
It is possible, however, to over-communicate. The stereotypical architect who spends time drawing pictures of systems that will never be has its roots in those who try to micro-manage the design. Even if it were possible to design every aspect of the system up front in detail, it would be inefficient. From the time wasted modeling duplicate (or nearly so) interactions to the bottleneck introduced by relying on the architect for all design, a useful tool can be turned into an impediment. Little wonder teams have thrown the baby out with the bath water. That being said, it is a waste to abandon useful techniques because of the potential for abuse. The key is to find a happy medium.
In “C4: context, containers, components and classes”, Simon Brown discusses a lightweight modeling process designed to capture architecturally significant information across different levels of detail using a Class Responsibility Collaboration (CRC) card metaphor. Context diagrams are used to picture the system under development in context with the rest of the technology environment (i.e. integrations) and those who will be using the system. Container diagrams capture the execution environment of the system: sites, services, databases, etc., visually depicting the major pieces of the system and their interconnections. Component diagrams illustrate the major groups of code that make up the containers. Class diagrams are used only when warranted. This system, which concentrates on the information and not the syntax or tool, makes perfect sense.
In the “Getting there from here” post, I mentioned a number of different UML diagrams I use during the architectural design process: use case diagrams to capture “who does what”, class diagrams to capture the key “things” the system deals with, package diagrams to illustrate system structure and activity diagrams to document the users’ interactions with the system in the course of a particular use case. All of these tend to be high level and relatively static aspects of the system. Likewise, they are aspects that are not readily reverse-engineered from code. As such, I maintain these as persistent artifacts that live from one release to the next for the life of the application.
When I’m doing lower-level design, class, activity, and sequence diagrams can be useful as well. These, however, I consider to be transient artifacts, useful for the moment, but not worth maintaining over the long-term. Particularly when you have access to tools that can synchronize with the code (I use both Visual Studio’s built-in features as well as Altova’s UModel), effort spent maintaining these types of diagrams is wasted. It makes far more sense to re-generate from the authoritative source: the source.
In my opinion, keeping a few simple principles in mind makes the difference between effective modeling versus just drawing pictures. First and foremost, is to focus on communication. Being understood is more important than being “right” (at least in terms of using the notation/tool). Next in importance is to know when to stop. Just enough detail provides value; too much extraneous information can cause confusion at worst and at best introduces delay. Lastly, know what to keep and what to throw away. Anything that illustrates existing code should be generated from that code rather than maintained manually.
Used correctly, modeling can be a powerful tool for communication. Communication and understanding are force-multipliers that contribute to success. A picture may well be worth a thousand words. It’s certainly quicker to put together (not to mention comprehend) a picture than a thousand words.