I am continuing my journey through the diagrams we use to understand and design solution architectures. I have already covered three of our "big four" in Solution User Diagram for Rapid Scoping, Information Flow Diagram: Go with the Flow!, and Master the Conceptual Solution Architecture Diagram, and I am ready to tackle the UML component diagram! It is the most technical of the primary four diagrams we use to depict a logical solution design. It clearly captures architecturally significant components and their connections, and the notation zooms in and out, so you can use it effectively to capture architectures at various levels of abstraction.
A component diagram depicts how you wire components together to form larger components or software systems. We stick to basic UML component model notation to create clear component designs. Check the UML benefits in my Activity Diagram article if you want a refresher on why we leverage the Unified Modeling Language notation. A component diagram is one of the seven structure diagrams in UML. Structure diagrams show what the elements of the system are (as opposed to behavior diagrams which show what the system does). We use the component diagram to depict the architecturally significant components of a solution architecture and how they are wired together.
As I mentioned, we stick to the essential elements of the UML component diagram notation to keep it simple for the people viewing the diagrams. Readers can understand them without any introduction, and a quick overview of a few elements of the notation can improve their comprehension even further. Plus, your users become more adept at understanding the diagrams over time because the notation is always the same.
Before I dig into more details about the notation, here is a quick 1-2-3 overview, along with an example. Introducing boxes, lollipops, and lines!
Component. This unassuming box is the belle of the ball on a component diagram! You use it to identify architecturally significant 1“Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change." - Grady Booch (2006), “On Design.” components in the scope of the architecture represented by the diagram. The plug-looking-icon in the upper right identifies the box as a component. It is labeled with a logical name and classified using a type (aka. “stereotype”).
Provided Interface. You attach a “lollipop” to a component to signify an interface provided by that component for other components to consume. The label indicates the capability provided by that interface. On a logical level diagram where we show services as components, the capability provided is the protocol used to interact with that component, like REST, FTP, or ODBC. We try to identify the highest level of abstraction for that protocol, so choose HTTP over TCP, REST of HTTP, etc. It is only useful for you to identify the protocol for industry standard protocols, so for any proprietary or custom protocol, we just label the lollipop "native".
Required Interface. Officially, this is added to a component to show that the component requires another component to provide a specific interface for it to operate. When using on solution architecture diagrams, we use this to connect a component to an interface that is provided by another component. That "U" shaped cup on the end quickly makes a mess on any architecture of significant complexity, so we usually omit the cup and use a line to make the connection. #protip
Note. These little post-its are pretty self-explanatory! We use it during drafting to capture open questions and later when publishing to provide clarifications. It is best if you have very few of them on on completed diagrams. If you have many, you are using the wrong diagram, capturing the wrong level of detail, or confused.
Dependency. A dotted arrow indicates that the component where the arrow originates is dependent on the component to which the arrow terminates. We use these sparingly because most times a dependency is obvious enough based on its placement or unnecessary to indicate at this level of diagram.
I have been using these to diagram solution architectures for two decades. I have tried many stereotypes, but have landed on the following that handle most situations. In a pinch, I go "off book" to handle exception cases, but I recommend that you not do that regularly! (Or else they aren't exception cases.)
|Application||A software program or executable component; can be something that runs on another runtime (like a configuration that runs in an application environment or virtual machine)|
|Datastore||A persistent storage location for data.|
|File||A, uh, file.|
|Node||A “logical” environment within which other components can run. In the olden days these were typically logical servers, but when you factor in mainframes on one end and cloud computing on the other, they become more vague logical constructs. These are the outer components in our "two-level" diagram approach and we usually omit the type on these.|
|Service||A discrete unit of functionality that can be accessed remotely by other components.|
|Job||Any batch run process, usually scheduled but not always. Like ETL/ELT jobs, command-line scripts, etc. Obviously, a "discrete unit of functionality" as well. Here's some rules of thumb: if your "discrete unit of functionality" is invoked using an API, its a service; if it isn't, it's a job (unless you run interactively using its own user interface, then an application).|
|Library||An object or function library used by other components on this list.|
|Package||A component representing multiples of some type (any of the above) where the details are not necessary, e.g. “OCR Services," "ETL Jobs," or "Scanned Documents."|
We are huge proponents of "just enough" diagramming. While we are huge fans of UML and the consistency (and guidance) it brings to diagramming, we use it to create clear fit-for-purpose architecture diagrams and don't get obsessed with a perfect model. We value clarity over completeness, focusing on what is necessary and only what is necessary to describe the architecture under discussion.
We break the rules when necessary, but let me offer a few bits of advice: (1) breaking the rules needs to be the exception and not the rule and (2) you don't break the rules until you are a master of the rules. The rules help you ask the right questions about a solution architecture. The rules also help you know when you are done: when you understand why each box, line, and lollipop is present and accounted for, you are done.