There are two great miracles in systems engineering – where the requirements come from and how you get from requirements to implementation. Where requirements come from is a topic for later (it need not be a miracle or a mystery). As for moving from requirements to implementation, that requires a blend of a creative and analytic thinking. The best path does not involve miracles. The best path moves from requirements to behavior to implementation, and threads are the key to tying together requirements and behavior. [more]
First, what is a thread? The integrated system behavior is the exhaustive specification of how a system behaves in response to any input under any conditions. A thread is the stimulus response path from a specific input (or combination of inputs) to the corresponding outputs under a defined set of conditions. In designing an automated teller machine (ATM), the integrated behavior describes all of the activities, items, and corresponding structure required to perform all required operations: dispense cash, accept deposits, provide account balances, perform self-tests, support cash reloads, etc. A thread would be the sequence of activities along with the corresponding structure and items required to accept a customer request for a savings account balance in the case of a valid request (valid account number and authentication).
So if a thread is a simplification of integrated behavior under very controlled conditions, what is the value? Generating threads may be perceived as unnecessary overhead. After all, if the objective is to develop the integrated system behavior which will be allocated to the physical architecture, let’s just develop the integrated system behavior. Unfortunately, attempting to make the leap from requirements to integrated system behavior for even a simple system appears to be a miracle. Working from a blank sheet of paper, there are so many requirements to consider and so many possible designs that it becomes difficult to start. It’s quite possible to be overwhelmed by the permutations and possibilities in this combined creative and analytic exercise. Simplifying the problem gets us started.
The objective of thread analysis is to gain insight into the way we want the system to behave. If we look at how we design the system behavior in response to specific stimuli under specific conditions, we narrow our scope and have a workable problem. We don’t overanalyze any given thread, instead looking for a solution that works within the constraints. The objective is not 100% completeness and precision. The objective is insight. From there, we move to the next thread and the next thread, gaining insight as we solve each micro-portion of the behavior.
How much is enough? That is far more art than science. Typically we need one thread for each use case, each system input and output, and each primary condition. As the design team tackles threads, the collective insight into the desired system behavior grows. At some point, the team reaches critical mass and is ready to undertake the system behavior itself. This is a leap though a much smaller leap than without threads. Appealing as it might be, there is no way to simply “add up” all of the threads to obtain the integrated system behavior. Even if you had every possible thread, the activities or functions on each thread are only valid within the set of assumptions for that thread. Taking an activity or a behavior sequence developed for the case of “provide savings account balance for a valid request” and assuming it is valid in the larger scope of customer requests and conditions (such as invalid authentication) is a notable error. Furthermore, thread analysis is generally performed by a team. Unless the team is drawing from a common library of functions or has solved an equivalent problem before, it is likely the approaches taken and terminology used is different. So the objective of thread analysis is insight. We stop thread development and proceed with the integrated system behavior when we believe we sufficiently understand both the problem and the solution.
So how do we derive threads in the first place? Each system input and output, use case, and combination of conditions define distinct classes of threads. One approach is to look at the system boundary diagram and define threads corresponding to each item that crosses the system interface. While that is a valuable technique, personally I like to start with use cases. (Note: The use case terminology has evolved somewhat over the years. Original Jacobson use cases were closer to threads or scenarios vs the modern UML/SysML use cases described here.)
Frequently use cases are leveraged with stakeholders to help elicit requirements. If we continue onward, they are a very valuable tool in bridging to integrated system behavior. Drawing a use case diagram helps identify behavior visible beyond the system boundary as well as the external systems and actors involved. This has similarities to the system boundary diagram, but use cases are closer to behavior than physical implementation. Then, the key is to ensure that each use case has stated preconditions and postconditions (without which a use case should be called a “useless case”). The preconditions and postconditions define the starting point and ending point for a thread. The engineering team’s job is to define a thread of behavior (structure, activities, and the corresponding inputs, outputs, and triggers) that connects the preconditions to the postconditions. This thread “elaborates” the use case.
As an example, consider the problem of a user request for an image. One use case would address the case of processing the user request when the image already exists in inventory. In this case, the precondition is the image is in inventory, and the postcondition is the user has received the desired image. A second use case addresses when the image must be obtained from external sources before being provided to the user. In this case, the precondition is that the image is not in our inventory. The postcondition is the user has received the desired image and the image has been stored for future use. In each case, we can imagine designing the necessary behavior to connect precondition to postcondition.
The specific notation and representation you choose to represent the thread is up to you. Typically thread analysis is focused on sequencing of functions, the corresponding behavioral constructs, and interactions with external systems. This makes EFFBDs, activity diagrams, and sequence diagrams prime candidates. Each is focused on activities (functions) and the exchange of items. EFFBDs and activity diagrams are more complete and explicit in terms of specifying the behavioral constructs. Sequence diagrams better highlight the exchange of data between systems. Because this is a thinking tool used for insight rather than a formal specification, being 100% technically complete is not the objective. That being said, this should still be treated as part of a model with the thread explicitly linked back to the use case (which relates back to the requirements) as opposed to simply drawing diagrams.
As the team develops more threads for a given system, you sense the point in time where you are ready to tackle the integrated behavior. Do not discard the threads you have developed. Though they do not mathematically add up to the integrated system behavior, they are essential artifacts that reflect the thinking and design rationale. These individual threads can be related to the integrated systems behavior they inform. They are also valuable tools for others seeking a white box understanding of your system – a manager or customer who needs some insight without understanding the full behavior, a new team member becoming acquainted with the system, or the test team seeking to fully exercise your system under all combinations of conditions.
As we pull threads in systems engineering, we don’t unravel the solution. Instead, we find that threads are valuable connectors between requirements and implementation. As they are built, threads help the project team develop essential insights and weave together the integrated systems behavior. Once created, threads provide limited glimpses into the behavior design and rationale. When preserved, threads serve the team in formal system verification testing during system integration. If we take the time up front to understand and pull threads, they serve us throughout the engineering lifecycle.