{"slug": "drawing-the-blueprint-flowchart-functional-diagram-and-sequence-diagram", "title": "Drawing the Blueprint: Flowchart, Functional Diagram, and Sequence Diagram", "summary": "The article describes a structured approach to software design, using the \"Post a message\" use case to demonstrate the sequential creation of three diagrams: a flowchart, a functional diagram, and a sequence diagram. It emphasizes that these diagrams must be built on a concrete data model (defined in a previous lesson) to transform them from sketches into precise specifications. The author argues for a fixed order—behaviour, then structure, then interaction—because each diagram serves as the necessary input for the next.", "body_md": "# Lesson 3 of *Build a Twitter Clone* - A Practical Guide to Software Modelling\n\nIn [Lesson 2](https://dev.to/eugene-zimin/the-blueprint-beneath-the-blueprint-designing-data-model-and-choosing-its-database-3bhl), we defined what `Bird`\n\nmust *remember*: two databases, tables within, every field traced back to a use case. Now it's time to draw what `Bird`\n\nmust *do*. Using `\"Post a message\"`\n\nas our single worked example, we construct all three diagrams in sequence - first a flowchart that traces the user action step by step, then a functional diagram that reads the required components directly off that flowchart, then a sequence diagram that shows exactly how those components talk. By the end, the use case that started as a sentence on a sticky note has a complete, traceable blueprint.\n\n## Introduction - The Foundation Is Ready\n\n[Lesson 2](https://dev.to/eugene-zimin/the-blueprint-beneath-the-blueprint-designing-data-model-and-choosing-its-database-3bhl) ended with a promise, and it's worth quoting precisely:\n\n\"That's where Lesson 3 picks up: with the data model as the foundation, we draw all three diagrams.\"\n\nThat moment has arrived. But it's worth pausing for a second to notice what's different now compared to where we started.\n\nIn [Lesson 1](https://dev.to/eugene-zimin/from-idea-to-blueprint-turning-a-vague-app-concept-into-something-you-can-actually-build-1a60), we introduced the idea of three diagrams - a flowchart, a functional diagram, and a sequence diagram - as three lenses on a single system. We explained the mental model, argued for the order, and left it there. No diagrams were actually drawn, and that was deliberate: a diagram drawn before the project is bounded and the data understood is a diagram you'll redraw.\n\n[Figure 1. The Foundation Is Ready](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafgc5ff3q079abfk9ild.png)\n\nIn [Lesson 2](https://dev.to/eugene-zimin/the-blueprint-beneath-the-blueprint-designing-data-model-and-choosing-its-database-3bhl), we did the bounding. We read `Bird`\n\n's three use cases for data clues, named two entities (`User`\n\nand `Message`\n\n), defined five tables across two databases (`ums`\n\nand `twitter`\n\n), and established the relationships that tie them together. The schema is real now: a `messages`\n\nrow has a specific shape - an `id`\n\n, a `content`\n\nfield capped at 280 characters, an `author_id`\n\npointing to a row in `ums.users`\n\n, and a `created_at`\n\ntimestamp. The `users`\n\nrow has a shape too. Every \"save the message\" step in every diagram we draw will refer to something concrete.\n\nThat concreteness is what changes everything. A diagram drawn on top of a real data model isn't a sketch - it's a specification. The boxes mean something. The arrows carry named fields. When a step says *\"validate the message,\"* we already know what the validation is checking (which is called validation criteria): a non-empty `content`\n\nstring, no longer than 280 characters, attached to an authenticated `author_id`\n\n. Nothing is left as a placeholder.\n\nThis lesson draws all three diagrams. We'll work in order - behaviour first, then the structure that behaviour implies, then the detailed conversation inside that structure - for the same reason we always work in that order: each diagram is the input to the next, and the input has to exist before the output can be correct.\n\n## A Quick Reminder: The Three-Lens Progression\n\nBefore we pick up the pen, one short bridge back to [Lesson 1](https://dev.to/eugene-zimin/from-idea-to-blueprint-turning-a-vague-app-concept-into-something-you-can-actually-build-1a60) - not a full re-teach, just enough to make sure the scaffold is standing.\n\nThe core idea is this: any software system can be understood from three distinct angles, and each angle demands a different kind of diagram.\n\n| Lens | The question it answers | The diagram | What you see |\n|---|---|---|---|\nBehaviour |\nWhat should the app do? |\nFlowchart | Steps, decisions, and outcomes - the system as a process unfolding in time |\nStructure |\nWhat parts must exist to make that behaviour happen? |\nFunctional diagram | Components and their connections - the system as a thing made of pieces\n|\nInteraction |\nHow do those parts talk to each other at runtime? |\nSequence diagram | Messages exchanged between components - the system as a conversation\n|\n\nNone of these is more correct than the others. A flowchart can't tell you what components to build. A functional diagram can't tell you what happens when a user submits an empty message. A sequence diagram can't tell you whether you've correctly scoped the feature. They are **complementary**, not competing - and you need all three because no single one is complete.\n\nThe critical habit is the **order**. You move behaviour → structure → interaction, and each step is derived from the one before:\n\n[Figure 2. The three-lens progression - each diagram derives from the one before](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1cqn5nl8mqxij3nzfje.png)\n\nThe reason the order is fixed: you can't know what components to build until you know what the system must do. And you can't describe the conversation between components until you know which components exist. Behaviour is the requirement; structure serves it; interaction lives inside structure.\n\nAn analogy for the progression.Imagine designing a kitchen. First you decide what the kitchen mustdo- prepare meals, store food, clean dishes. That's behaviour. Then you ask whatpartsmust exist to support each of those tasks: a cooktop, a refrigerator, a sink. That's structure, falling out of behaviour. Finally, you trace the specific workflow - the chef moves from the refrigerator to the prep surface to the cooktop, in that order, passing ingredients along. That's interaction, living inside the structure. You couldn't have designed the workflow without knowing the layout. You couldn't have designed the layout without knowing the tasks. The order is the method.\n\n## Lens 1: Behaviour - Drawing the Flowchart\n\nA flowchart answers one question: **what does the system do, step by step?** Not what parts it has. Not which component calls which. Just the sequence of actions and decisions that carry a user from \"I want to post a message\" to \"it's done\" - or to an error, if something goes wrong along the way.\n\nThat makes the flowchart the right place to start. It captures the requirement in its purest form, before any implementation choices have been made.\n\n### Building it step by step\n\n**Step 1 - Name the start and end points.**\n\nThe flow begins the moment the user presses \"Post\" - that is, when the system receives a submission. It ends either with a new row in `twitter.messages`\n\nand a confirmation to the user, or with an error message and no row written. Name those endpoints first, before filling in anything in between.\n\n**Step 2 - List the actions in order.**\n\nWalk the happy path first - what happens when everything goes right? For \"Post a message,\" that sequence is:\n\n- Submit a message\n- Pass the authentication check - is the user logged in?\n- Pass the permissions check - is the user allowed to post?\n- Pass content validation - is the message valid?\n- Save the message to the database\n- Confirm success to the user\n\nSix steps. Two are actions, three are decision gates, one is a confirmation. That's a healthy breakdown - the logic is explicit without becoming an implementation manual.\n\n**Step 3 - Add the decision points.**\n\nThree decision diamonds gate the happy path:\n\n-\n**Is the user logged in?** If no → redirect to the login page. After a successful login the user is returned to the submission step - a loop, not a dead end. -\n**Is the user allowed to post?** Not every account has posting rights - a read-only or suspended role is blocked here. If no → shared Error node → END. -\n**Is the message valid?**(Non-empty? Within 280 characters?) If invalid → shared Error node → END.\n\nNotice that the two error branches converge on a single `Error`\n\nnode before reaching `END`\n\n. This is an intentional design choice in the diagram: the system's response to a permissions failure and a content failure is the same kind of thing - an error returned to the user. Merging them keeps the diagram clean and makes that equivalence visible.\n\n**Step 4 - Connect and label.**\n\nArrange the steps top to bottom, connect them with arrows, and label every arrow leaving a decision diamond. The labels on the branches (\"yes / no\", or more descriptively \"valid / invalid\") are what make the diagram readable at a glance.\n\n### The flowchart\n\n[ Figure 3. Flowchart for \"Post a message\"](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndj15078ai1yo0txid9i.png)\n\n### What this diagram tells us - and what it doesn't\n\nThe flowchart is intentionally silent on *how* each step is implemented. It doesn't say which component checks authentication, or what library validates the string length, or whether the database write is synchronous. Those details don't belong here. What the flowchart does - and does well - is make the **logic** visible: the decisions, the branches, the outcomes. That's the entire job of Lens 1.\n\nNotice that the data model already sharpens the language. The \"Save message\" step doesn't just say *\"save the message\"*- it names the fields: `author_id`\n\n, `content`\n\n, `created_at`\n\n, writing into `twitter.messages`\n\n. That specificity comes directly from [Lesson 2](https://dev.to/eugene-zimin/the-blueprint-beneath-the-blueprint-designing-data-model-and-choosing-its-database-3bhl). The flowchart is still high-level, but it's no longer vague.\n\nWith the behaviour fully drawn, the next question asks itself: **what parts must exist to make each of these steps happen?** That's Lens 2 - and the answer comes directly from reading this flowchart.\n\n## Lens 2: Structure - Reading the Functional Diagram off the Flowchart\n\nThe flowchart is done. We know what \"Post a message\" must do - the steps, the decisions, the branches. Now a different question takes over: **what parts must exist inside the system to make each of those steps happen?**\n\nThis is where most beginners get into trouble. They open a new diagram and start inventing components - a generic `AuthService`\n\n, an `APIGateway`\n\n, a `DatabaseLayer`\n\n- based on instinct or prior experience. The result is a diagram that reflects what the developer already knew, not what the use case actually requires.\n\nThere is a better method. The functional diagram doesn't need to be invented. It can be **read directly off the flowchart**.\n\n### The method: scan every step, ask one question\n\nFor each step in the flowchart, ask: *what component must own this responsibility?* The answer names a block. Do that for every step, merge the ones that belong together, and the structure falls out of the behaviour.\n\nLet's walk through the flowchart step by step.\n\n| Flowchart step | Responsibility | Component |\n|---|---|---|\n| User submits message | Sends the HTTP request | Frontend Client |\n| Is the user logged in? | Identifies who is making the request | Twitter Service |\n| Redirect to login | Returns the login page | Frontend Client |\n| Is the user allowed to post? | Fetches the user record and checks for the `PRODUCER` role |\nTwitter Service → UMS Service\n|\n| Is the message valid? | Enforces content rules (non-empty, ≤ 280 chars) | Twitter Service |\n| Save message | Writes the row to `twitter.messages`\n|\nTwitter Service → MySQL Database\n|\n| Confirm success | Returns `201` with the created message |\nTwitter Service → Frontend Client\n|\n| Return error | Returns `403 Forbidden` to the client |\nTwitter Service → Frontend Client\n|\n\nTwo things stand out immediately. First, the **Twitter Service** carries the most weight: it receives the request, performs content validation, and orchestrates the database write. But it doesn't hold user data - that lives in UMS. So for the permission check, the Twitter Service calls the **UMS Service** via an internal HTTP request, retrieves the user's roles, and decides whether to proceed. This cross-service call is the architectural heart of the feature.\n\nSecond, there is no separate `API Gateway`\n\nor `Auth Service`\n\nin `Bird`\n\n. The Frontend Client talks directly to the Twitter Service on port `9001`\n\n. Role checking is a responsibility of the Twitter Service itself, delegated to UMS on demand - not a standalone component sitting in between.\n\nThis gives us four components: the **Frontend Client**, the **Twitter Service**, the **UMS Service**, and **MySQL Database**.\n\n### The functional diagram\n\n[ Figure 4. Functional diagram for ](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl813m8f32djv1op3akk5.png)`Bird`\n\nThe diagram reads as a set of named blocks connected by labelled arrows. The arrows carry the nature of the relationship - not the step-by-step logic (that's the flowchart's job) but the structural dependency: the Frontend Client sends requests to the Twitter Service; the Twitter Service calls UMS to validate the user; the Twitter Service reads and writes MySQL directly. Each arrow represents a real, named communication channel in the codebase - HTTP on `:9001`\n\nfor the UI-to-service call, `WebClient`\n\nfor the service-to-service call, JDBC for the database connection.\n\n### What this diagram is - and isn't\n\nA functional diagram is a **map of components**, not a map of steps. It answers \"what pieces exist and how are they connected?\" - not \"what happens first?\" The flowchart and the functional diagram are not redundant; they answer different questions and each is incomplete without the other.\n\nNotice also what the functional diagram deliberately omits: there are no arrows labelled with field names, no decision branches, no error paths, no sequence numbers. Those details live in the sequence diagram. Here, the goal is structural clarity - a reader should be able to see at a glance what `Bird`\n\nis made of and how the pieces relate.\n\nWith the components named and connected, one question remains: **how exactly do they talk to each other during \"Post a message\"?** That's the sequence diagram - and now that we know which components exist, we can finally draw it precisely.\n\n## Lens 3: Interaction - The Sequence Diagram\n\nThe flowchart told us *what* \"Post a message\" does. The functional diagram told us *what components* exist to do it. The sequence diagram answers the last question: **what do those components say to each other, in what order, when the feature actually runs?**\n\nThis is where the previous two diagrams earn their investment. Every component named in the functional diagram becomes a lifeline. Every step in the flowchart becomes a message on one of those lifelines. Nothing is invented - it's assembled from what we already know.\n\n### From components to lifelines\n\nA sequence diagram is built around **lifelines** - vertical columns, one per component, representing each participant in the interaction. Reading the functional diagram directly, our lifelines are:\n\n-\n**Frontend Client**- the browser, initiating the request -\n**MessageController**- the entry point inside the Twitter Service, receiving the HTTP call -\n**MessagesService**- the orchestrator: calls UMS, checks roles, triggers the database write -\n**UMSConnector**- the thin HTTP client that talks to UMS via`WebClient`\n\n-\n**UMS Service**- the external service that owns user identity and roles -\n**JdbcMessageRepository**- the DAO that executes the SQL insert -\n**MySQL**- the database that persists the row\n\n### Reading the flow\n\nThe messages between lifelines follow the exact path the codebase executes. Let's trace it:\n\n- The\n**Frontend Client** sends`POST /messages/message`\n\nwith`{ author, content }`\n\nto the**MessageController**. -\n**MessageController** deserializes the body into a`Message`\n\nDTO and delegates to**MessagesService** via`createMessage(message)`\n\n. -\n**MessagesService** needs to verify the author - it doesn't hold user data, so it calls**UMSConnector** with`retrieveUmsData(/users/user/{id})`\n\n. -\n**UMSConnector** fires a non-blocking`WebClient GET`\n\nto the**UMS Service**. -\n**UMS Service** returns a`UserDto`\n\ncontaining the user's roles. -\n**MessagesService** unpacks the response via`HttpResponseExtractor`\n\nand inspects the`Roles`\n\n. If the user is not a`PRODUCER`\n\n- the flow terminates here with a`403 Forbidden`\n\nback to the client. - If the role check passes,\n**MessagesService** calls`createMessage(message)`\n\non**JdbcMessageRepository**. -\n**JdbcMessageRepository** executes`INSERT INTO messages`\n\nagainst**MySQL**(converting the UUID via`DaoHelper`\n\n). -\n**MySQL** returns`ok`\n\n. - The saved\n`Message`\n\ntravels back up:**JdbcMessageRepository**→** MessagesService**→** MessageController**→** Frontend Client**as`201 { message }`\n\n.\n\n### The sequence diagram\n\n[Figure 5. Sequence diagram for \"Post a message\"](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjikmyhmwdhsjvjjroq8x.png)\n\n### What this diagram shows that the others couldn't\n\nLook at the `alt`\n\nblock in the middle of the diagram. That's the permission check - the same diamond in the flowchart, the same role-checking responsibility assigned to `MessagesService`\n\nin the functional diagram. But now it has an exact form: a comparison against the `PRODUCER`\n\nrole, returning `403 Forbidden`\n\nif it fails, with the response passing back through `MessageController`\n\nto the client.\n\nThis is **traceability** working in practice. The validation step in the flowchart → the `MessagesService`\n\nblock in the functional diagram → the `HttpResponseExtractor → User → Roles`\n\ncall chain in the sequence diagram. One idea, three levels of resolution.\n\nNotice also what the sequence diagram adds that neither previous diagram could: **the reactive chain**. The `UMSConnector`\n\ncall is non-blocking - `MessagesService`\n\nissues the `WebClient`\n\nrequest and the rest of the chain executes inside a `.flatMap()`\n\n. The sequence diagram makes this visible through the activation boxes: `MS`\n\nstays active while `UC`\n\nand `UMS`\n\ndo their work, then resumes. That concurrency detail is invisible in both the flowchart and the functional diagram.\n\nWith all three diagrams drawn, one use case - \"Post a message\" - now has a complete, layered blueprint. The next section puts all three side by side and shows what traceability looks like end to end.\n\nLet's pause before moving on and do something the three diagrams individually don't do: put them side by side and trace a single idea across all of them.\n\nTake the permission check - the moment the system decides whether the author is allowed to post. Here is where it lives in each diagram:\n\n| Diagram | Where the permission check appears | What you can see |\n|---|---|---|\nFlowchart |\nThe diamond \"Is user allowed to post?\" branching to `Error` or continuing to validation |\nThe logic - two outcomes, one decision |\nFunctional diagram |\nThe arrow from `MessagesService` labelled \"check roles contains PRODUCER\" pointing to `Roles`\n|\nThe ownership - which component holds this responsibility |\nSequence diagram |\nThe `alt` block: `HttpResponseExtractor → User → Roles` , branching to `403 Forbidden` or `INSERT`\n|\nThe mechanics - what data moves, in what order, producing what result |\n\nSame check. Three levels of resolution. You could point at the diamond in the flowchart, follow it to the `MessagesService`\n\narrow in the functional diagram, and land on the `alt`\n\nblock in the sequence diagram - and at each step you'd learn something the previous diagram couldn't tell you.\n\nThat property is **traceability**: the ability to follow a single requirement from its highest-level expression down to its lowest-level implementation without losing the thread. It's what separates a set of diagrams that decorate a document from a set that actually functions as a blueprint.\n\n[Figure 6. One feature, three views - the permission check traced across all three diagrams](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffk1k8s8gfv65tivh8u7v.jpg)\n\nNotice also what traceability reveals in the other direction. The sequence diagram shows that the `403 Forbidden`\n\nresponse travels back through `MessageController`\n\nbefore reaching the client - a detail invisible in both the flowchart (which just says \"Error → END\") and the functional diagram (which shows `MessageController`\n\nconnected to `GlobalExceptionHandler`\n\nwithout explaining when). The diagrams don't just repeat each other. Each one completes the picture in a direction the others leave open.\n\n## Limitations and Open Questions\n\nThree diagrams drawn, one use case traced. Before closing, it's worth being clear about what this process is - and what it isn't.\n\n**Diagrams go stale.** Every diagram in this lesson reflects the codebase as it stands today. The moment a new field is added to `messages`\n\n, or the permission model changes, or `UMSConnector`\n\nis replaced by a shared auth library - the diagrams need updating. A diagram that isn't maintained becomes misleading faster than no diagram at all. The discipline of drawing diagrams is only half the work; the other half is keeping them honest.\n\n**This is a snapshot, not a specification.** The diagrams here describe what `Bird`\n\ndoes, not what it must do. A specification would go further - stating invariants, error contracts, performance bounds, and edge cases. These diagrams are the foundation of a spec, not the spec itself. They answer \"how does it work?\" not \"how must it always work?\"\n\n**Over-modelling is a real risk.** Drawing all three diagrams for every feature in a large system would consume more time than it saves. The three-lens approach is most valuable at decision points: when designing a new feature from scratch, when onboarding someone to an unfamiliar part of the system, or when debugging behaviour that contradicts the mental model. Applied indiscriminately, it becomes ceremony rather than engineering.\n\n**These diagrams are not UML.** Readers familiar with the Unified Modelling Language (UML) will notice that the diagrams in this lesson borrow UML conventions - sequence diagram lifelines, flowchart decision diamonds - without following the full UML standard. That's deliberate. UML is precise and complete, and its precision comes at the cost of accessibility. However when you move to production systems with formal specification requirements, UML or C4 may be the right choice.\n\n## What's Next\n\nThree lessons in, and `Bird`\n\nhas a bounded scope, a real data model, and a complete three-lens blueprint for its core feature.\n\nWhat it doesn't have yet is a working API. The diagrams show that a `POST /messages/message`\n\nendpoint should exist, that it must accept `{ author, content }`\n\n, that it must call UMS before writing to the database - but none of that is running code yet.\n\n**Lesson 4** is where the diagrams meet the wire. We'll define the API contracts and endpoints that connect `Bird`\n\n's components - what each service exposes, what it expects, and what it returns. The sequence diagram already told us that `POST /messages/message`\n\nmust exist, that it calls `GET /users/user/{id}`\n\non UMS, and that both exchanges carry specific payloads. Lesson 4 makes those contracts explicit and formal: request shapes, response shapes, status codes, and the communication protocol between the Twitter Service and UMS.\n\nThe diagrams were never the destination. They were the clearest possible way to know what to build before building it.", "url": "https://wpnews.pro/news/drawing-the-blueprint-flowchart-functional-diagram-and-sequence-diagram", "canonical_source": "https://dev.to/eugene-zimin/drawing-the-blueprint-flowchart-functional-diagram-and-sequence-diagram-537c", "published_at": "2026-05-23 20:45:57+00:00", "updated_at": "2026-05-23 21:01:31.164924+00:00", "lang": "en", "topics": ["developer-tools", "data", "enterprise-software"], "entities": ["Bird", "User", "Message", "ums", "twitter"], "alternates": {"html": "https://wpnews.pro/news/drawing-the-blueprint-flowchart-functional-diagram-and-sequence-diagram", "markdown": "https://wpnews.pro/news/drawing-the-blueprint-flowchart-functional-diagram-and-sequence-diagram.md", "text": "https://wpnews.pro/news/drawing-the-blueprint-flowchart-functional-diagram-and-sequence-diagram.txt", "jsonld": "https://wpnews.pro/news/drawing-the-blueprint-flowchart-functional-diagram-and-sequence-diagram.jsonld"}}