Skip to content
Browse

article

Use Case Modeling Patterns in SysML v2

  • published =
  • author = Tim Weilkiens

This post walks through four iterations of one SysML v2 use case. It is an example of a modeling approach from a simple use case via a use case with messages to a use case with actions.

The example is a delivery drone handing over a parcel. The drone hovers above the drop zone. The recipient enters a delivery code in an app, the drone verifies it and prompts the recipient, and the recipient requests the release of the parcel.

The iterations are:

  1. The first idea: subject, actor, objective. Nothing more.
  2. 2a: A first message: the actor sends a message to the subject, between named event occurrences.
  3. 2b: Message-owned events: the same semantics, but the events are the message’s own ends, so no names need to be invented.
  4. 3: Performed actions: the subject’s message ends become actions the system performs in the context of the use case.

The four iterations live side by side in one package so they can be compared. In a real model, it is one use case that evolves. The shared definitions are:

package DeliveryDroneUseCases {
    part def <DD> DeliveryDrone {
        action verifyRecipient;
        action releaseParcel;
    }
    part def Recipient;

    item def DeliveryCode;
    item def HandoverPrompt;
    item def ReleaseRequest;

    // use case definitions of the iterations follow
}

The actions verifyRecipient and releaseParcel are needed only in iteration 3. In practice, they are discovered there and then added to the system of interest.

Iteration 1: The first idea

The first iteration captures only who is involved and why the use case exists. The subject is the system of interest, the actor is outside of it, and the objective states the goal in the stakeholders’ words.

use case def HandOverParcel1 {
    subject drone : DeliveryDrone;
    actor recipient : Recipient;
    objective {
        doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
    }
}

General view of the use case HandOverParcel1 of the delivery drone, created with Cameo Systems Modeler

Figure 1: General View created with Cameo Systems Modeler

This is enough to agree on scope and naming. It says nothing yet about how the recipient and the drone interact. That is the question for the next workshop.

Iteration 2a: A first message between events

The second iteration adds the first message: the recipient transmits the delivery code to the drone. This is the beginning of a sequential communication, and it is the part that can be elaborated very well in a workshop with stakeholders: “And then? What does the drone answer?”

use case def HandOverParcel2a {
    subject drone : DeliveryDrone {
        event occurrence deliveryCodeReceived;
    }
    actor recipient : Recipient {
        event occurrence deliveryCodeSent;
    }
    objective {
        doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
    }
    message transmitDeliveryCode of DeliveryCode
        from recipient.deliveryCodeSent to drone.deliveryCodeReceived;
}

Sequence view of the use case HandOverParcel2a: the recipient transmits the delivery code to the drone (created with AI)

Figure 2: Sequence View created with AI

The important detail: the message ends are event occurrences, not the actor and the subject themselves. The ends of a message are events (similar to UML and SysML v1). A part has events: its creation and termination. With from recipient to drone, the message would be sent when the recipient ceases to exist and received when the drone comes into existence. That is nonsense, at least in most cases. The event occurrences are the points in the lifetime of the actor and the subject where sending and receiving happen.

Iteration 2b: Let the message own its events

Iteration 2a has a small annoyance: every message needs two event names, and deliveryCodeSent and deliveryCodeReceived carry no information that the message name does not already carry. Iteration 2b is a variant with a different textual notation but the same meaning.

use case def HandOverParcel2b {
    subject drone : DeliveryDrone {
        event transmitDeliveryCode.targetEvent;
    }
    actor recipient : Recipient {
        event transmitDeliveryCode.sourceEvent;
    }
    objective {
        doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
    }
    message transmitDeliveryCode of DeliveryCode;
}

The message is declared without from and to. Instead, the actor and the subject each declare an event that reference-subsets the message’s own source or target event. The semantics are the same as in 2a: the event in the recipient is where the message is sent, the event in the drone is where it is received. There is no need to invent names for the events anymore. The message name is the only name, and it is the one the stakeholders use.

Iteration 3: Message ends become performed actions

In the workshop, the conversation continues: the drone verifies the code, prompts the recipient, and releases the parcel on request. The drone does something in between the messages. Iteration 3 makes this explicit. The message ends in the subject are no longer events but actions the drone performs in the context of the use case. Successions between the messages define the order.

use case def HandOverParcel3 {
    subject drone : DeliveryDrone {
        perform action check ::> verifyRecipient;
        perform action release ::> releaseParcel;
    }
    actor recipient : Recipient {
        event occurrence deliveryCodeSent;
        event occurrence releaseRequested;
        event occurrence handoverPromptReceived;
    }
    objective {
        doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
    }

    message transmitDeliveryCode of DeliveryCode
        from recipient.deliveryCodeSent to drone.check;
    message promptHandover of HandoverPrompt
        from drone.check to recipient.handoverPromptReceived;
    message requestRelease of ReleaseRequest
        from recipient.releaseRequested to drone.release;

    first transmitDeliveryCode then promptHandover;
    first promptHandover then requestRelease;

    first start then drone.check;
    first drone.check then drone.release;
    first drone.release then done;
}

AI-generated sequence view of the use case HandOverParcel3 with the messages between recipient and drone; the actions on the right lifeline are not SysML v2 notation

Figure 3: AI-generated view. It is based on the SysML v2 Sequence View, but the actions on the right lifeline are not part of SysML v2.

Three things change compared to iteration 2:

  • The actions are owned by the system of interest. verifyRecipient and releaseParcel are defined in DeliveryDrone. The use case only references them with perform action … ::>. The use case describes how the system behaves in this context; it does not own the system’s behavior.
  • The semantics fit. A message is received at the start of its target occurrence and sent at the end of its source occurrence. With actions as ends, this is exactly what we want: when transmitDeliveryCode is received, check starts; when check ends, promptHandover is sent.
  • The actor still uses events. The recipient is outside the system of interest. We do not model its behavior, only the points where it sends and receives messages.

The successions first … then … define the order of the performed actions within the use case, from start to done. These successions implicitly also specify the order of the messages and make the successions between them obsolete, but we kept them to be more explicit. The messages and the successions together form a consistent picture: check must complete before release can start, and release starts only when requestRelease arrives.

Iteration 3 as an action flow view

The same use case definition can be shown in an action flow view. The sequence view emphasizes the communication between the recipient and the drone; the action flow view emphasizes the flow of performed actions inside the use case.

Action flow view of the use case HandOverParcel3 showing the flow of the performed actions, with the messages added by AI

Figure 4: View created with AI based on a view created with Cameo Systems Modeler. The view is valid SysML v2. The AI has added the messages.

Both views show one model, not two. The successions are the solid arrows, the messages are the dashed arrows into and out of the performed actions. This is where the use case meets the functional architecture: the performed actions are references to actions of the system of interest, ready to be refined in the functional and logical architecture.

The complete model

package DeliveryDroneUseCases {
    part def <DD> DeliveryDrone {
        action verifyRecipient;
        action releaseParcel;
    }
    part def Recipient;

    item def DeliveryCode;
    item def HandoverPrompt;
    item def ReleaseRequest;

    use case def HandOverParcel1 {
        subject drone : DeliveryDrone;
        actor recipient : Recipient;
        objective {
            doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
        }
    }

    use case def HandOverParcel2a {
        subject drone : DeliveryDrone {
            event occurrence deliveryCodeReceived;
        }
        actor recipient : Recipient {
            event occurrence deliveryCodeSent;
        }
        objective {
            doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
        }
        message transmitDeliveryCode of DeliveryCode
            from recipient.deliveryCodeSent to drone.deliveryCodeReceived;
    }

    use case def HandOverParcel2b {
        subject drone : DeliveryDrone {
            event transmitDeliveryCode.targetEvent;
        }
        actor recipient : Recipient {
            event transmitDeliveryCode.sourceEvent;
        }
        objective {
            doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
        }
        message transmitDeliveryCode of DeliveryCode;
    }

    use case def HandOverParcel3 {
        subject drone : DeliveryDrone {
            perform action check ::> verifyRecipient;
            perform action release ::> releaseParcel;
        }
        actor recipient : Recipient {
            event occurrence deliveryCodeSent;
            event occurrence releaseRequested;
            event occurrence handoverPromptReceived;
        }
        objective {
            doc /* The recipient receives the parcel at the drop zone,
             * and only the authorized recipient can release it. */
        }

        message transmitDeliveryCode of DeliveryCode
            from recipient.deliveryCodeSent to drone.check;
        message promptHandover of HandoverPrompt
            from drone.check to recipient.handoverPromptReceived;
        message requestRelease of ReleaseRequest
            from recipient.releaseRequested to drone.release;

        first start then drone.check;
        first drone.check then drone.release;
        first drone.release then done;
    }
}

All articles