Communicating Your Designs
Introduction
"Software Architecture is the shared understanding that the expert developers have of the system.”
-- Martin Fowler
Software design can only work if all of the developers on the team have the same understanding. Crafting a perfect system design is only valuable if you can effectively communicate it to others. This is where design documents and diagrams come in. They are the blueprint of your system, and they help you communicate your design to other developers, stakeholders, and even your future self. They ensure that everyone is on the same page and that the system is built as intended.
While not every system deserves documentation, having a clear and concise design document can be a huge help. It can act as a useful reference for developers, a guide for new team members, and a way to ensure that the system evolves in a consistent and coherent way.
Design Documents
Some engineers take the approach of not writing design documents, arguing that the code is the documentation. They see the phrase "Working software over comprehensive documentation" in the Agile Manifesto and use that as an excuse to skip documentation completely. This is not what the authors intended. They recognized that documentation has value, it just shouldn't be created at the cost of working code. While the code can act as documentation to some extent, it is not a substitute for a well-written design document. Code can be complex and hard to understand, especially for new developers. A design document provides a high-level overview of the system, making it easier for developers to understand the system's architecture and design decisions.
Not every system deserves a design document. If you're building a small, throwaway prototype, then a design document is probably overkill. If something is going to take more than a month to build, or if it's going to be maintained by multiple developers, you should consider including a design document as part of the project.
Types of Design Documents
It is common to create several different types of design documents when working on a project. Each document serves a different purpose and is targeted at a different audience. Some of these documents will be discarded once the initial project is complete, while others will be maintained and updated throughout the life of the project. It just depends on the value they provide.
The exact types of design documents and their names will vary depending on the source. Some documents that you might create during the project lifecycle include:
Planning or Requirements Document
The first document typically created for a greenfield project is a planning or requirements document. If you are working on a well established system this document is probably long gone. The document outlines the goals of the project, the requirements, and the constraints. It is a high-level document that provides an overview of the project and helps the team to get the project off the ground.
- What problem is this system intended to solve and how will it solve it?
- Who are the stakeholders? What are their needs and expectations?
- What value does it provide? Can we measure that value?
- What are the constraints? (e.g., budget, time, technology, etc.)
- What are the risks? How will we mitigate them?
- Who will be doing the work? What are their roles and responsibilities?
- Are there alternative solutions? Why did we choose this one?
The main audience for this document is the organization's leadership team, project managers, and other stakeholders. This is the group who will have the final say in whether or not the project will be prioritized and funded. Including this document in your process ensures that everyone is on the same page and that the project is aligned with the organization's goals.
Creating this document is a collaborative effort that involves working with stakeholders and leadership to define the project's goals and requirements. You may need to conduct interviews, do surveys, or observe potential users in action to gather the necessary information. While it isn't a technical document, it is important to get the technical team involved early in the process to ensure that the project is feasible and that the requirements are clear.
This document is mostly about the requirements and constraints of the project, rather than the technical details. During the early stages of development I might use this document as a reference, but once the project is underway, it's likely to be discarded. Some of the information in this document will be moved to other documents, while other parts will be discarded entirely.
Architecture Document
An architecture document provides a high-level overview of the system's structure and its dependencies. It describes the system's components, which external systems it needs to interact with, how they communicate, and the design decisions that were made.
This is usually the first document I create after the project has been approved. My goal is to capture external dependencies so that I know which teams I need to work with and what APIs I need to integrate with. I also want to capture the high-level design decisions so that I can communicate them to the rest of the team. We should also capture the non-functional requirements, such as performance, scalability, and security, so that we can design the system to meet those requirements.
This document will be used by the development team throughout the project to guide their work. It needs to be a living document that is updated as mistakes are identified and as the system evolves. It will also be used by new developers who join the team to help them understand the system's architecture, and by engineers outside of the team who need to understand how it intersects with their work. Maybe a security teams needs to understand our authentication system to make sure it meets company standards, or a DevOps team needs to understand the deployment environments we're using.
Component Design Document
The architecture document provides a high-level overview of the system's structure, but it doesn't go into detail about how the code itself is structured. That's where the component design document comes in. This document provides a detailed description of each component in the system, including its responsibilities, its dependencies, and its interactions with other components. This document is the most important document for developers, as it provides the information they need to implement the system. It ensures that all developers have the same understanding of how the system is structured and which components are the most important.
It should answer questions like:
- What components are in the system and how do they interact?
- What are the responsibilities of each component?
- Which design patterns are used and why?
- What testing strategy are we using? Are we enforcing some kind of code quality?
- If a new developer wants to add a feature, where should they start?
This document should be the first place developers look when they need a refresher on how the system is structured. If they're not sure where some logic should fit, this doc should be their guide. It should be updated as the system evolves, so that it remains an accurate representation of the system's design.
Interface Design Document
The final type of design document I create is the interface design document. This document describes the interfaces that the system exposes to other systems. It includes the APIs, the data formats, and the protocols that are used to communicate with the system. This document is used by other teams who need to integrate with the system, such as the front-end team, the mobile team, or external partners. It ensures that everyone is on the same page about how the system's interfaces work and how they should be used.
This often takes the form of an OpenAPI Contract, which is a machine-readable document that describes the API in a standard format. This document can be used to generate client libraries, server stubs, and documentation. It can also be used to validate requests and responses to ensure that they conform to the API's contract. Using this approach can help to ensure that APIs are versioned correctly and that they are backwards compatible. If you create the contract early in the process, you can share it with other teams to allow them to start working on their integrations before the API is complete.
If you're working on a system that isn't a service, then this document doesn't always make sense. You might want to replace it with user mocks or wireframes that describe how the user interface should look and behave. Many full-stack developers that I've worked with prefer to approach design from the user's perspective, making some variant of this document very helpful.
Tips for Writing Design Documents
If you're brand new to writing design documents, it can be a bit overwhelming. There are many templates available online, but they can be overly complex and difficult to follow. They can be a reasonable starting point, but I recommend simplifying them to make them more approachable. These templates are typically designed for use by project managers, who need to track progress and ensure that the project is on track. As an engineer, you need to focus on the technical details and ensure that the system is built correctly.
It's important to remember that these are technical documents, not marketing documents. They should be written in a clear, concise, and technical manner. Your objective is clear communication, not impressing the reader with your writing skills. You should avoid jargon and acronyms that the reader might not understand. You should also avoid using overly complex language or long-winded explanations. The goal is to make the document as easy to read and understand as possible.
- Write as concisely as possible. Bullet points or numbered lists will help you to communicate your ideas in fewer words.
- Let the diagrams do the talking. A well crafted and meaningful diagram is better than any paragraph of explanation, but make sure your diagrams can stand on their own.
- Use consistent terminology. If you use a term in one place, use it everywhere. This will help to avoid confusion and ensure that everyone is on the same page.
- Be precise whenever possible. If you have data for something, include it. If you have a specific requirement, state it.
- Read your own document, pretended to be a new developer going through onboarding. Does it make sense? Are there any gaps in the explanation?
Where to Store Design Documents
Once you've written your design documents, you need to decide where to store them. There are many options available, but I recommend storing them with the code in the same version control system as the project. This allows you to track changes to the documents over time, so that you can see how they have evolved. More importantly, it minimizes the effort required to keep the documents up to date. If the documents are stored separately from the code, then they're more likely to become stale. By storing them with the code, you help to ensure that they remain up to date and accurate. You still need to be disciplined about updating them, and to develop a culture of reviewing them as part of the PR process.
Diagrams
One of the easiest and most effective ways to communicate your design is through diagrams. A picture is worth a thousand words, and a well-crafted diagram can convey complex ideas in a simple and easy-to-understand way. Diagrams can be used to show the system's architecture, its components, its dependencies, and its interactions. They can be used to show how data flows through the system, how requests are processed, and how errors are handled. They can even be used to show how the system is deployed, how it scales, and how it is monitored. There are many different types of diagrams that you can create, depending on what you're trying to communicate.
Unfortunately, most diagrams are terrible. They are poorly drawn, overly complex, and difficult to understand. They are often created as an afterthought, rather than as a key part of the design process. This is a mistake. A diagram that is only created as a part of a design meeting loses all of its value as soon as the meeting is over. Diagrams should be treated with the same care and attention as the code itself. They should be reviewed and critiqued by other developers, so that they accurately reflect the system's design.
Types of Diagrams
Boxes and Arrows
The least structured approach to diagramming is to use simple boxes and arrows, usually drawn on whiteboard during a meeting. This is the most common type of diagram, and it is used to show how components in the system interact with each other. Each component is represented by a box, and each interaction is represented by an arrow. The boxes should be labeled with the component's name, and the arrows labeled with some details about the interaction. This type of diagram is simple and easy to understand, but it can quickly become cluttered and difficult to read if you're not careful. Be sure to label everything, and to use consistent notation.
These diagrams are best used as part of a planning discussion. They can help you to quickly sketch out the system's architecture and identify potential problems, and because you are physically present, any ambiguity can be quickly resolved.
Unfortunately, these diagrams are weak as documentation. They are difficult to update, and they don't provide much context. Without someone present to explain them, they don't have much value on their own. They are best used as a starting point, and then replaced with more detailed diagrams as the design evolves.
CRC Cards
Class-Responsibility-Collaboration (CRC) cards are a way of diagramming the responsibilities and important relationships for the classes in a system. Each card represents a class, and it is divided into three sections: the class's name, its responsibilities, and its collaborators. The class's name is written at the top of the card, and its responsibilities are written in the middle. The class's collaborators are written at the bottom. The cards are then arranged on a table or a whiteboard to show how the classes interact with each other.
While not strictly a diagram, they capture the same basic details that a diagram would. Every approach we're describing is seeking to capture the same information, just in different ways and at different levels of abstraction.
UML Diagrams
Unified Modeling Language (UML) is a standardized way of creating diagrams that describe the structure and behavior of a system. It is a powerful tool that can be used to create many different types of diagrams, including class diagrams, sequence diagrams, and state diagrams. UML is an absurdly complex language, and it's becoming increasingly common for developers to not know how to read it.
I rarely use UML diagrams simply because of the time they take to create. Their specificity can be useful in some cases, but I find that they are often overkill. They are best used when you need to communicate with a team that is already familiar with UML, or when you need to create a diagram that is very precise and detailed. At which point, you need to question why you're not just writing code.
Sequence Diagrams
Sequence diagrams are a type of UML diagram that show how objects in the system interact with each other over time. They are used to show the flow of control between objects, and to show how messages are passed between them. Sequence diagrams are useful for showing how a particular feature works, and for identifying potential problems with the design.
I frequently use sequence diagrams when I am trying to understand an existing system. Because they can be constructed as you explore the code, they are a great way to document how a system works. I also use them when I want to explain to a stakeholder the lifecycle of some event or data. They are a great way to show how a system will behave in a particular scenario.
Network Diagrams
Network diagrams are a type of diagram that show how the system's components are connected to each other. They are used to show how data flows through the system, how requests are processed, and how errors are handled. Network diagrams are useful for showing how the system is deployed, how it scales, and how it is monitored.
A common use for network diagrams is to show how data is protected as it moves through the system. This can be useful for explaining to stakeholders how their data is secured, and for identifying potential security vulnerabilities. I frequently create these as part of a security review, to ensure that the system is secure and that data is protected.
Other Types of Diagrams
There are many other kinds of diagrams used in various parts of the software development process. Things like flowcharts, deployment diagrams, wireframes, and entity-relationship diagrams can all be useful in different contexts. I recommend learning about these different types of diagrams and experimenting with them to see which ones work best for you. The key is to use the right diagram for the right situation
Diagramming Strategies
The question now, is how do you decide which s to use? There are many different approaches to diagramming, each with its own strengths and weaknesses.
4+1 Architectural View Model
The 4+1 Architectural View Model is a way of organizing your diagrams into different views, each of which shows a different aspect of the system. The four views are:
-
Logical View: This view focuses on the functionality that the system offers the end users. It helps to answer questions about what the system does and how it does it.
-
Process View: Shows the threads and components that will be interacting with each other. It can help to identify potential bottlenecks and performance issues.
-
Development View: This view shows how the system is built and how it is tested. It is used to guide development and to ensure that the system is built correctly.
-
Physical View: Shows the system hardware and how the components are distributed and deployed. It is used to show how the system is deployed and how it scales.
-
Scenarios: The final view is a set of scenarios and use cases that connect the views together.
This approach is useful for organizing your diagrams and ensuring that you cover all of the important aspects of the system. When communicating with stakeholders or other developers, you can refer to the appropriate view to show them the information they need.
While I've used this approach in the past, I found that I rarely created all of the views. I typically focus on the logical view, and then create additional views as needed.
C4 Model
The C4 Model, created by Simon Brown, is a way of organizing your diagrams into different levels of abstraction. The four levels, in order from highest level to lowest level, are:
-
Context Diagram: The highest level diagram shows how the system will interact with its most important external systems. In many cases, the boundary for this diagram is based on the organization itself. The goal is to identify which other teams or systems you need to work with.
-
Container Diagram: Each container in this diagram would be an application or data store. This diagram shows how the system will interact with its dependencies, including other systems, databases, and external APIs.
-
Component Diagram: This diagram shows the system's components. These are the major structural building blocks of the system. Each component is labelled with its name, responsibilities, and any important technical details.
-
Class Diagram: This diagram shows the system's classes, including its attributes and methods. It is rarely necessary to create diagrams at this level. In most cases the code itself can fulfill this role.
This approach is useful for organizing your diagrams and ensuring that you cover all of the important levels of abstraction. Different levels of abstraction are useful for different audiences, so you can refer to the appropriate level to show them the information they need.
Tips for Creating Better Diagrams
Creating good diagrams is a skill that takes time to develop. It requires practice, experimentation, and feedback.
Keep it Simple
No single diagram can ever answer all of the questions you might have about a system. Your objective is to create a diagram that can answer some specific questions. If you try to answer too many questions with a single diagram, it will quickly become cluttered and difficult to read. Any information not specifically related to the question you're trying to answer should be left out.
It's common to want to add details to a diagram to make it more complete, but this is a mistake. The more details you add, the more difficult the diagram will be to read. You should strive to create the simplest diagram that can answer the question you're trying to answer. If you need to answer multiple questions, create multiple diagrams.
Make the Diagram Useful on its Own
The biggest issue with the boxes are arrow diagram that are often created in design meetings is that they are useless outside of that meeting. Even if you take photos, they leave too many gaps in the explanation. You should strive to create diagrams that are useful on their own, without any additional context. This means that you need to label the components, the interactions, and any important details. You should also use consistent notation, so that the reader can quickly understand what they're looking at.
Accuracy doesn't matter
"All models are wrong, but some are useful." -- George Box
If we need a perfect representation of the system, then we should just look at the code. The purpose of a diagram is to communicate an idea, not to provide a perfect representation of the system. It's okay if the diagram is not 100% accurate, as long as it conveys the idea you're trying to communicate.
Use Consistent Notation
Part of the appeal of UML is that it offers a consistent notation for creating diagrams. The problem is that it offers too many options that are too specific to niche use cases. It turns out that any consistent notation works just as well. Define a set of symbols and stick to them. This will make your diagrams easier to read and understand.
Use Color and Labels
The goal of every diagram is to convey information efficiently and effectively. Color and labels can help you to do that. Use color to group related components, to highlight important details, and to make the diagram more visually appealing. Use labels to provide additional context, to explain complex interactions, and to make the diagram more informative.
Get Feedback
Even if you think your diagram is perfectly clear, it's possible that someone with less familiarity with the system will find it confusing. As the creator of the diagram, you have a lot of context that the reader doesn't have. Ask peers for feedback. If they find something unclear, then you need to make it clearer. Clarity, in this case, is in the eye of the beholder.
Tools for Creating Diagrams
There are many tools available for creating diagrams, ranging from simple drawing tools to complex diagramming software. The best tool for you will depend on your needs and your budget. Here are some of the tools I've used in the past:
-
Lucidchart: A web-based diagramming tool that is more powerful than Draw.io, but also more complex. It has a wide range of features and templates, making it a good choice for more complex diagrams. This is the tool I use most often, simply because my company has a license.
-
Excalidraw: A free, web-based diagramming tool that is simple and easy to use. It is great for creating quick sketches and brainstorming ideas. It is not as powerful as Lucidchart, but it is more lightweight and easier to use.
-
Draw.io: A free, web-based diagramming tool that is easy to use and has a wide range of features. It is a great tool for creating simple diagrams quickly.
-
Microsoft Visio: A desktop-based diagramming tool that is part of the Microsoft Office suite. It is a powerful tool that is widely used in the industry, but it is also expensive and complex.
-
Pen and Paper: Sometimes the best tool for creating a diagram is a pen and paper. It is quick, easy, and doesn't require any special skills. It's also a great way to get feedback from others, as you can quickly sketch out ideas and iterate on them.
When selecting a tool, try to choose one that allows you to create diagrams quickly and easily. The goal is to create diagrams that are useful, not to spend hours creating the perfect diagram. If you find yourself spending too much time on a diagram, then you're probably overthinking it. Remember, the goal is to communicate an idea, not to create a work of art.
Conclusion
Communicating your designs is a critical part of the software development process. Design documents and diagrams are the blueprint of your system, and they help you to communicate your design to other developers, stakeholders, and even your future self. They ensure that everyone is on the same page and that the system is built as intended. By creating well-crafted design documents and diagrams, you can ensure that your system is built correctly and that it meets the needs of your users.