the design before working on the detail. Non-functional requirements tend to manifest themselves as properties rather than as functions of the final SRS and it is important that a considered approach is made to the following:
a) Defensive code: Defensive code has the disadvantage of adding code to the application and of making it more difficult and potentially harder to test. Against this should be weighed the increase in safety integrity gained by preventing errors from propagating and by having the ability to detect an unexpected error and return the SRS to a safe state. Before any defensive code is written, the behaviour of the compiler when it detects statically
determinable constructs should be well understood, as the compiler may optimise out the defensive code. The option to include or exclude compiler generated checks should be considered, as should the likely consequences of a compiler generated check detecting an error. Defensive code may be efficiently implemented using `exception' features of the language if these are included within the language subset. Defensive code should follow a consistent plan, and should be identified as such by source code comments. In general, consideration should be given to adding defensive code to:
i) protect the software against the hardware (for example range check inputs to the SRS and self-test routines such as RAM tests);
ii) protect the hardware against the software (for example range checks outputs even when they can be statically determined always to be within range);
iii) protect the software against the software (for example range check inputs and outputs for each procedure, add `others' clauses to `CASE' structures, explicitly check assumptions and defend against domain incorrect errors such as divide by zero).
b) Fault-tolerance: Fault-tolerance may be necessary where high availability is required, but it should be used with care. Like defensive code, it complicates the SRS and may make analysis difficult. Fault tolerance should be founded on statically determinable criteria (such as two parallel, equally justified SRS systems) rather than on dynamic features such as dynamic recovery blocks. A case may be made for recovery blocks, provided that the behaviour of the code is determinable at all times. Behaviour under both persistent and intermittent fault condition should be considered. `Fail safe' measures, such as graceful degradation or placing the software into a safe inoperable state should be considered, especially where the software detects that its own behaviour or its inputs are not within the designed parameters.
c) Reliability: Reliability of software relates only to design faults (correctness), as software does not wear out (unlike hardware). Strictly, the correctness of software is either 0 or 1, since errors are either present or not. From a practical point of view, quantifying software reliability is therefore a difficult issue and is concerned not just with the presence of errors, but with the circumstances in which the errors are revealed, and the consequences of the errors. The only means by which achieved reliability can be measured directly is based upon statistical testing (such as that suggested under validation testing). High reliability in
software should be achieved by the diligent application of the principles in this Standard. It is important, however, that the Design Team appreciate that there may be a difference between
35.4(Cont)
safety and reliability: a system with an unreliable `on' switch, that prevents it operating may well be totally safe, although completely unreliable. For reliability, the Design Team should consider both availability (ie the probability of the system generating outputs on demand; starting up; running without crashing and running without halting due to an error) and reliability of the output (ie the likelihood of an incorrect, inaccurate or inappropriately timed output).
d) Accuracy: The Design Team should assess the ability of the algorithms to produce outputs which are both stable and meet the accuracy requirements of the SRS. If, as previously
discussed, floating point arithmetic is deemed inappropriate, the Design Team will be left with the option of fixed point or scaled integer, or more complex solutions such as modular arithmetic. Whichever solution is adopted, the Design Team or V&V Team should undertake a computational methods study to ensure that the outputs are within the specified accuracy, that discrete algorithms model continuous, real behaviour with sufficient accuracy and that overflow (or underflow) does not occur.
e) Capacity: When the amount of input or data that can be processed is variable, for example because of interrupts, or the requirement to store and process records, the Design Team should ensure that they can predict the maximum demands that could be made upon the system. The system should be shown to be robust and operable at the maximum demands, and stress tests of maximum capacity should be included during the testing phase. The Design Team should also ensure that the target has the required capacity for the SRS and should check:
i) stack sizes;
ii) buffer and queue sizes; iii) static memory allocation;
iv) dynamic memory (heap) allocation; v) temporary file or other memory usage.
f) User-interface: Where the SRS has an interface directly to a user or operator, extra care should be taken in its specification and design. A prototype should be constructed and the end user should be involved in ensuring that the SRS will function satisfactorily under
operational conditions. Where the safety of the system could be affected by the actions of the user as a result of output from the SRS or via input to the SRS, human factors experts should be involved in designing and checking the user-interface and testing the usability of the final system.
g) Software configuration and version identity: All parts of the SRS should be identifiable and should have a recorded version identity. It should be possible, via the configuration management system, to relate the version of each part to the versions of all other parts to which it relates. The Design Team should consider adding explicitly embedded identifiers, including a version identifier, into the final version of the object code. Where configurable or
35.4 (Cont)
programmable units are used in a larger system, the use of a start up or self test procedure which checks the identity of the parts of the SRS should be considered. Behaviour in the event that incompatible versions are detected should be defined.