6 Things We’ll Need for the Next Step
Before we go on, we need to describe certain things on their own, so that we can effectively use those definitions in the following discussions.
6.1. Preconditions, Post-conditions, Triggers, Requirements, Dependencies, and Assumptions
Precondition: Anything that must be true in order to use a module’s functionality is a precondition. For example, if you need to insert your car’s key into the ignition key-slot in order to start the car, then the insertion of the proper key is a precondition to starting the car. In the software realm, many systems have logging in as a precondition to the use of most functions.
Post-condition: A post-condition is any change to the system or to session-specific information as a result of executing some path through the function. For instance, let’s say that you use the Unix “touch” command to create or modify a file. After you “touch” a file, it exists, and shows the modification date and time as the time that “touch” was executed. The fact that the file has been created or shows as modified is a permanent post-condition to having executed the “touch” command. If you log into an application, then being logged in is a session-specific post condition, in that it’s only valid for the remainder of the session. In some applications, there are also document-specific post-conditions.
Trigger: A trigger is something that causes some action to occur, or some module to be entered, given that all preconditions (if any) are true. For instance, in starting a car using a key in an ignition switch, inserting the key is the precondition, and turning the key is the trigger. The post-condition is that the car has (hopefully) started. A trigger may be a user action, something that sensors pick up, a clock reaching a certain time, or any other event. In SQL databases, a trigger can be added to a table using a CREATE TRIGGER command, which causes some code to execute before or after certain events (adding, modifying, or deleting a record) occur.
Requirement: A requirement is something that the system (hardware, software, something else, or a combination of those) must be or do. In requirements documentation, requirements apply to the system being developed only, and not to users. Requirements apply to developers, but only indirectly.
Dependency: A dependency is not a requirement or a precondition, but something that will be required. For instance, once we’ve started the car, driving the car depends on having unobstructed land in front of it. If there’s a tree in front of the car, the car will have to stop, back up, or go around it. The car also needs land in front of it. Driving into the water is not advised. But, you can start driving without having to worry about the trees or water. So, unobstructed land is not exactly a precondition for driving, since it’s not something that we need to check before driving, but instead something that must be true for the entire time. We depend on that, and so it’s a dependency. Don’t get too hung up on this. There are things that are wobblers between preconditions and dependencies. In those cases, you’d just have to pick a categorization and go with it.
Assumption: An assumption is something that you reasonably assume to be true, or true in most cases. If something is both an assumption and a dependency, then list it as a dependency only. For instance, in a web browser, we might optimize the use of HTTP and HTTPS (Secure HTTP) web-pages, even though we can also use the browser for perusing FTP (File Transfer Protocol) and SFTP (Secure FTP) sites, because we can justifiably assume that that when the user types a URL without a protocol, that the user intends to use HTTP.
Primary path (or sequence) and alternate path (or sequence): The primary path through a function, functionality, or module is the path that we expect events to take. For instance, someone coming to a web-site and logging in would normally involve the steps (1) going to the web-site, (2) the web-site displaying, (3) the user clicking on “Log in”, (4) a “Log in” page displaying, (5) the user entering a name and password and clicking on the submission button, and then (6) the system validates the name and password, and then redirects the user to the main page in the logged-in state. In one alternate path, step 6 would vary in that the name/password might not be accepted. In another alternate path, there might be a missing field. In the missing field case, depending on where checking code executes, this could be spotted in step 5 or step 6. Note that for any given function, there may be zero or more alternate paths.
Sheldon’s recommendation: Always check such alternate cases in the equivalent of step 5 and step 6. Checking in step 5 prevents a post of missing data, and checking in step 6 prevents external bad data that can come about as a result of a hacking attempt or the failure of the protective browser-side JavaScript to execute.
Stimulus and response: A stimulus is just what the word normally means, but in a requirements specification, it only applies to the system. A response is also the normal English meaning, but in a requirements specification, it only applies to what the system does about the stimulus.
6.2. Functional and “Nonfunctional” Requirements
“Functional requirements” and “Non functional requirements” are probably not the best terms to have used for requirements documentation purposes, but those are the terms in use by the industry, so we’re all stuck with them. As used, a “functional requirement” is a requirement that directly specifies a requirement on the system’s main and visible functionality. A “nonfunctional requirement” is one that doesn’t relate directly to any one function, or which seldom occurs. For instance, in a web application, the fact that a particular page will do a particular thing constitutes the page’s functional requirements. The fact that the page and all other pages will be immune to SQL injection attacks is a “nonfunctional requirement”. (An SQL injection attack is one in which commands in the SQL language are inserted into a text field, in hopes that the back-end program will be tricked into executing the SQL code.)
6.3. Functional Composition & Decomposition
In a large, complicated project, even after we’ve gathered or elicited all the requirements, we can’t just sit down and document them all. We have to break things down into logical areas. There are two reasons for this.
In the bottom-up method, where you’ve gotten a lot of distinct requirements, you may need to group them up or arrange them into some sort of order that makes sense. In Agile projects, where you tend to get a lot of distinct requirements thrown at you from all sides, they use points (a key point of the story, not a numeric thing that can be added), user stories, themes, and epics.
A story point is a key point in the story. A story point is also a thing that happens or must happen. For instance, in the elevator example, one story point is that a passenger breaks the light beam. Another story point is that the doors retract because of the beam being broken. You combine these points into user stories that each make some sense on their own. (Don’t confuse story points, or story elements, with Scrum’s numeric points, such as a “3 point story”.)
These user stories can be combined into themes, or related stories, and further combined into epics of related themes. In medium-sized projects, themes and epics will be the same things. When you combine them, try to list them out in one of these three orders:
- In the order in which they’ll have to be built,
- In the order in which these use cases will logically or typically occur, or
- In an order that makes them easiest to understand, with the fewest forward references.
More often, though, you’ll have to go through “functional decomposition”. In an Agile project, this will involve figuring out what the epics are, and for each epic, figuring out what the themes are, and for each theme figuring out what the stories are, and for each story figuring out what the key points. In a typical Waterfall project, you’ll be figuring out what the systems are, and within the systems, subsystems, then assemblies, modules, and functions, and finally key functional points.
An example from one of Sheldon’s assignments: We were going to build a big automated factory to put components together. Robots would have to get the components, visually line them up, weld parts together, and then send those built items to other parts of the factory. The builder robots would interface with robotic conveyor belts, and there would be robotic supply robots, supplying the welders with solder, for instance. So, we’ve broken the factory concept down to three types of robots. Now, onto the welder robots. The original design called for the welding assembly, the vision system, a manipulator to get things from the conveyor to the work stage and back, a work stage that could grip things, and a user interface used for training. (It turned out that the vision system working together with the welding system could move parts around adequately, so the manipulator was removed.) So, now we’ve got the robot’s components. Within the welding assembly was the feed mechanism for the solder, the weld unit, the sensors, the various axes of motion, and so on. Within the axes of motion, there were various directions.
Basically, you break a big problem down into a number of smaller problems, until you have one of a size clearly documentable as a series of requirements. (When the programmer gets the requirements, those will be broken down into smaller and smaller problems, until each is one line of code.)
6.4. How Things Can Go Wrong
Leaving out preconditions or dependencies can mean that extra error checking has to be done later, or worse, a situation in which the needs and facts are at odds. Getting the triggers wrong will often mean that a needed function never comes into play. Not stating your assumptions can mean that the entire project is built on a false premise, which can cause a 100% failure when first used, or worse, that failure can occur after acceptance. Leaving out the “nonfunctional” requirements can lead to security flaws and general dissatisfaction.
6.5. Discussion Questions
- Sometimes a requirement may be at the wobbly edge of functional (specific) verus nonfunctional (nonspecific). Do you have any feelings or advice about how to make such categorizations?
- What do you think is the proper amount of time to take a response without posting something interesting for the user to look at?
- Do you think it’s easier to work compositing micro-requirements into a cohesive theme, or easier to take a broad vision and break it down?