CPSC 333 --- Monday, February 12, 1996 Transaction Analysis (Steps A.2.2 -- A.2.4 for DFDs with Transaction Flow) A.2.2) "Partition the DFD." Since you decided that this diagram exhibits "transaction flow" in Step A.2.1, it should be easy to identify - a "Transaction Center" --- a single process in the diagram that has the properties described above (in the details for Step A.2.1). Note: Pressman calls this process an "invoke command processing bubble" in his description of transaction analysis. You should be able to group the remaining processes in the data flow diagram into the following sets: - Input Flow (also called "Command Acquisition") These are the processes that prompt for and receive a "command" --- the data that is supplied by one or more terminators to the transaction center - Activity Paths --- two or more sets of data flow diagrams that represent major subsystems that are "activated by" the transaction center. There is usually one activity path for each one of the different kinds of command that the transaction center can recognize, and the transaction center usually "activates" exactly one activity path each time it receives a command. Note: If you used the "structured analysis" process I described in class to produce the set of data flow diagrams that are now being processed, then this description of the process will be fine. If you used a "DFD development" process that also looks for, and combines together, processes with similar functions, then you may discover that two or more activity paths share processes, so that the "activity paths" aren't completely separate. In this case, you could either - duplicate each shared process, putting a copy into each activity path that uses it. This will allow you to "make the rules work" now, and when you look for and fix design problems later on, you'll have the chance to eliminate the redundant modules that will result in the "first draft" structure chart; or - choose the order in which you'll process the activity paths (as part of Step A.2.4) --- and "put each process" into the earliest activity path (for this ordering) that you can. Then, the first activity path you process will be "complete." For later activity paths, when you encounter a process that's "missing" because it was allocated to a different activity path that needed it, then there will already be a module for that process in the structure chart. Add a connection (or connections) to this module, rather than duplicating it. Since we're growing structure charts from "the top down," you should end up with a module that can be called by several others. For the rest of these notes I'll assume that activity paths really are completely separate. Recall that the method for architectural design we're now describing is a "two (or more) pass" method: In a "first pass" produce a "first draft" structure chart, and in one or more later passes, look for and fix design problems. We *will* have a chance to look for, and remove, redundant modules later on --- and it's easier to me to describe (and for you to implement) the first pass if I make this assumption now. A.2.3) "Perform First Level Factoring." Add a "main module" for the system. Give this a name that describes the function of the entire system corresponding to the (sub)DFD you're currently processing. If you're *just* starting (so that your "structure chart") is currently empty this will be the main module for the entire system. Otherwise, this will be a child of one of the other modules that have already been added to the structure chart. Add a "command acquisition" controller and make it a "child" of the main module. Add a second child for the main module. This will be the module corresponding to the "transaction center" and it should have the same name as this DFD process. A.2.4) "Perform Second Level Factoring." Add modules that correspond to the "input flow" (or "command acquisition") processes, in essentially the same way that you added modules for "input flow" processes during transform analysis: Start with a set of processes that pass data directly to the transaction center, and create modules that are children of the "command acquisition" controller for each one of these. Then, follow data flows backwards from these processes toward the terminators, adding modules that are children of the ones you've added already as you go. This would be the same process as the one you used for transform analysis, if you had an "input flow boundary" separating the input flow processes from the transaction center. Treat each activity path as a data flow (sub)diagram and produce a structure chart for it by applying step A.2 recursively. Make the main module for each of the resulting structure charts a child of the transaction center's module, in order to connect the structure charts together. Pressman gives a "transaction analysis" example on pages 382--387 of his "Practitioner's Guide." Unfortunately, he also includes the recursive application to the activity paths at the same time, so that it might not be as easy as it should be to see what you get, by applying this method to the overall DFD *before* applying it recursively to the activity paths. A.3) "Add data areas and data flows to the structure chart." Apply the method described at the end of the handout, "More Information about Entity Relationship Diagrams," in order to obtain a set of data tables from the system's ERD. Create a "data area" on the first cut structure chart for each of the data tables (using the same name for the data area as for the data table) you obtained. Then add a data area for each of the DFD's data stores *that doesn't correspond to anything on the ERD* --- that is, for each data store that represented a "register," storing only a small (fixed) amount of information. Draw each of the data areas on the structure chart using the symbol given in the notes for Lecture 14 for inclusion on a "first draft" structure chart. Draw an arrow down to a data area from each module that corresponds to a DFD process that communicates directly with the corresponding data store(s) on the DFD, either to read data, or to create, modify, or delete data. Don't "decorate" the arrows on the structure chart to show creations or deletions (even though we "decorated" the arrows on the DFDs). Data "flows" on a structure chart along the connections between modules, or between modules and data areas. You never show a data flow between two modules unless one of the modules is shown as being able to "call" the other module directly (as a subroutine). Similarly, you never show a data flow to or from a module, from or to a data area, unless the module's already been shown as being able to "call" the data area directly. Data flows directly to or from terminators on the DFDs aren't included at all on the system's structure chart. All other data flows --- which are between two processes, or between a process and a data store --- will correspond to one *or more* data flows on the structure chart. First consider a data flowing from "Process A" to "Process B," and suppose that "Module A" and "Module B" on the structure chart correspond to "Process A" and "Process B," respectively. If "Module A" can call "Module B," either directly or indirectly --- so that there's a directed path (of arrows "pointing forward") from "Module A" to "Module B" on the structure chart --- then show the data flow as being passed down this path from Module A to Module B --- so that Module A calls another module, including the data flow as an input. If that module isn't "Module B,", then module calls another module, including the data flow as an input, and so on, until Module B is called and receives the data flow as an input. If, instead, "Module B" can call "Module A," either directly or indirectly, then show the data flow as being passed *up* the path from "Module A" to "Module B" --- so that Module A returns the data flow as an output to one of the modules that can call it. If that module isn't Module B, then *that* module returns the data flow as an output back to one of the modules that can call it, and so on, until Module B receives the data flow from one of the modules it can call. *Usually,* if either of the above cases applies, then there is a direct connection from "Module A" to "Module B" --- that is, either "Module A" can directly invoke "Module B," or "Module B" can directly invoke "Module A," and then there be a *single* data flow on the structure chart that corresponds to the data flow on the DFD. If neither of these cases applies, then there is a third module, "Module C," that can (either directly, or indirectly) call both Module A or Module B, and that is the "lowest" module in the structure chart that can call both. Module C will "usually" be one of the "main modules" that was added during transform or transaction analysis in order to process a piece of the DFD. Show the data flow as being passed (by reporting it as output) along the sequence of modules from Module A up to Module C, and then being passed (as an output) along the sequence of modules from Module C down to Module B. Note: There will typically be *lots* of design problems remaining to be detected and corrected in the "first draft" structure chart corresponding to this approach. However, the structure chart does have *some* desirable features: - Because of the way "input flow" and "output flow" processes are mapped to modules, those processes communicating directly with terminators tend to be near the bottom of the structure chart and somewhat "localized." The modules near the top --- especially the controllers --- only see data in internal, "logical" format. As well, the syntax and semantics of inputs should have been checked, and incorrect inputs "rejected," before the data gets this far. - The calling structure is appropriate if a "command line" interface is being used, or if a *very simple* menu-based system --- the kind that can be supported using a simple VT100 terminal --- is being developed: The main module (indirectly) prompts for, and receives input, then sends that down to the central transform for processing. The resulting outputs, still in internal form, are received back from the central transform, and then passed down to the output flow controller, who sends them farther down to be formatted and, eventually, transmitted to the terminators. This program structure worked quite well in the 1970's and (perhaps) early 1980's, when languages like C or Pascal were used for development, and when "highly interactive" interfaces weren't typically used. It localizes those modules dealing directly with I/O devices so that these are easy to find and modify, if the devices themselves are changed. It prevents "input bound" or "output bound" systems --- systems for which a change in an I/O device would require changes to most of the modules in the system (including the controllers, near the top of the structure chart). However, it *doesn't* lead to a program structure that supports a "highly interactive" interface --- one you need a windowing system and a mouse for --- because it "assumes" that the *system* has substantial control over the order in which input is received, rather than the user. It also doesn't (easily) provide a structure that allows you to take advantage of some of the features that newer programming languages --- including object-oriented languages. We'll continue to study it because it *can* be of some use --- for some *parts* of systems with a more modern interface --- and it includes ideas and some methods that have also included in more recent design methods.