A shipping team needs to decide what happens when a carrier times out while creating a label. The first sketch has three boxes, "Shipping," "Queue," and "Carrier," with arrows between them. Everyone understands the happy path. Then someone asks whether a timeout means the carrier created a label that the shipping service has not recorded. The arrows cannot answer.
That is the point at which notation becomes a practical choice. The team needs a drawing that separates system ownership from the order of events. More shapes will not fix an unclear question; neither will adopting a formal notation for every drawing.
For this fictional example, an order service submits a shipment request to a shipping service. The shipping service stores a shipment record and adds a label job to a queue. A worker calls an external carrier API, then stores the carrier's label identifier. The carrier may accept a request while its response is lost. We will assume the request has a stable idempotency key that the carrier honors, so a retry with that key does not create a second label. That contract needs checking with a real carrier. The example leaves out address validation, billing, and other production concerns.
The informal sketch gets the discussion moving
Start with boxes for the order service, shipping API, shipment store, queue, worker, and carrier API. Label the arrows with actions: "submits shipment," "stores pending shipment," "enqueues label job," and "requests label." Draw the carrier outside the boundary of the service the team owns. A reader can now see that the worker, rather than the order request, makes the carrier call.
This takes little preparation and lets the team move or rename things while the design is still unsettled. Its cost is that the drawing has no agreed grammar. Is "Shipping" one process, the whole service, or a group of programs? Does a worker-to-carrier arrow mean a network request, a dependency, or a possible retry? An informal drawing works if its labels and legend answer those questions for this meeting. It becomes expensive when each reader has to infer a different meaning.
There is no prize for replacing a clear sketch with standard symbols. Keep it as the working drawing if the decision is simply whether the carrier call belongs in the order request or in a worker. Add the missing failure path before claiming the design is settled.
C4 makes the system boundary less negotiable
If this drawing will be reused by engineers joining the service, a C4 container diagram gives its boxes a more stable meaning. In C4, a "container" is an application or data store, not necessarily a Docker container. The shipping API, worker, and shipment store can be shown as distinct runtime parts of the shipping system. The order service and carrier API are neighboring systems. The relationships say what each part does and, where useful, how it communicates.
That structure makes a specific review question easier: who owns the pending record, and which running part calls the carrier? It also keeps infrastructure placement out of this decision. C4 has a separate deployment diagram for mapping software instances to an environment. A queue box needs care here. If the shipping team owns a queue resource as part of its system, label that boundary; if a separate messaging system owns it, show that external system and the shipping team's use of it. Calling every rectangle a C4 container would erase the distinction the notation is meant to provide.
C4 names four core levels of static structure: system context, container, component, and code. You need not draw all four. A context diagram may be too broad for the worker decision, while a component or code diagram may bury it in implementation detail. The container view is a useful middle ground here. Its cost is maintaining consistent names and boundaries as the service changes. It still cannot show whether the worker receives an acknowledgement before or after the carrier creates a label. C4 also offers dynamic diagrams for runtime interactions, so the method is not limited to static pictures.
UML pays off when the order of events is the argument
"Use UML" is incomplete advice. The Object Management Group describes UML as a family of diagram types, including component and deployment diagrams for structure and sequence and state machine diagrams for behavior. The UML specification defines the language. A class diagram would add little to this carrier timeout discussion. A sequence diagram can put the relevant participants and messages in time order.
For this decision, the sequence should begin after the order service has submitted a shipment. Show the worker taking a job, reading the pending shipment, sending createLabel with the shipment's idempotency key, and waiting for a carrier response. Then show two outcomes. On success, the worker records the label identifier and completes the job. On timeout, it leaves the shipment pending and arranges a retry using the same key. If the carrier accepted the first call but the response was lost, that retry must avoid creating another label. The team also needs a way to recover the existing label identifier, whether from the retry response or a separate lookup. The diagram does not prove that the carrier supports either behavior; it exposes the contracts the team must verify.
A sequence diagram is worth the effort when reviewers disagree about which event happens first or which failure branch owns a state change. It can also become crowded quickly. Adding every database read, logging call, and retry timer would make the uncertain carrier outcome harder to see. A state machine diagram might be the better next artifact if the team's real dispute shifts to all valid shipment states and transitions. UML's precision helps only when the chosen diagram type matches the disputed behavior and the team uses its symbols consistently. A few lifelines drawn casually should be described as "sequence-style," not as a claim of full UML compliance.
Make one scoped choice
For this review, keep a labeled C4-style container view for the service boundary and add one short UML sequence diagram for the timeout and retry path. Name the idempotency assumption beside that path and assign someone to verify the carrier contract. The two drawings share names, but they answer different questions: where the responsibilities live and what happens when the response is missing.
If the team is still deciding which parts exist, use the informal sketch until those boundaries stabilize. Lycana can help at that stage: speak or type the shipping components and their relationships, then revise the drawing as the boundary discussion changes. That does not make the result a compliant C4 or UML diagram; use the notation's own rules when precision matters. If the carrier contract is already proven and the review only concerns service ownership, the container view may be enough. If shipment state transitions become the source of defects, draw those transitions explicitly and check them against the implementation. The notation changes when the question changes, not because one style has won a contest.


