Requirements

Requirements management records what a system must, should or may do, who wrote and owns each requirement, how it evolved, and how the requirements of different engineering disciplines relate to each other: an electrical requirement has its counterpart in the FPGA firmware, and this one in the software.

Data Model

The requirements model of pyEDAA.Reports.Requirements is built from typed values: no file format is read yet. Every element carries key-value pairs for the information the model has no field for (element["effort"] = 3).

  • RequirementSpecificationthe root - a version and an optional name
    • Persone.g. Patrick Lehmann - a real person: an author or owner of items
    • Personae.g. a reviewer - a role a user acts in, as in a user story
    • Labele.g. a product variant
    • Documente.g. a datasheet - attached to items
    • Layere.g. electrical, FPGA firmware or software
    • Requiremente.g. EL-1 - kind, obligation, state, layer, personas, labels, documents
      • Requiremente.g. EL-1.1 - a child requirement refining it
      • Linke.g. FW-1 is the counterpart of EL-1
      • HistoryEvente.g. opened, split, closed
    • SpecificationIteme.g. DES-1 - a specification item, which specifies requirements
  • The RequirementSpecification registers every person by user ID, and every persona, label, document and layer, every requirement and every specification item - also the child items - by its ID. An ID is unique among the elements of a class; a duplicate raises the duplicate error of its class, e.g. DuplicateRequirementError - each a DuplicateElementError and a RequirementsError. Each registry is a dictionary property, e.g. Labels, with an iterator taking an optional predicate, e.g. IterateLabels().

  • The root’s Version is the version of the specification itself; its name is optional.

  • A Persona is a role a user of the system acts in, e.g. an administrator, a reviewer or a quality inspector. A real person is a Person with a user ID, a name and an optional e-mail address. A person has no parent: AddPerson() registers it, and the same person may be registered in several specifications.

  • Every element knows the element containing it - Parent - and its specification - Root. Assigning a parent, in the constructor or later, adds the element to it and passes the specification on to the elements below it. An element, which already has a parent, raises an AlreadyInSpecificationError - an AlreadyInHierarchyError.

  • An item refers only to personas, labels, documents and layers of its own specification. An element or person of another specification raises a NotInSameSpecificationError - a NotInSameHierarchyError: it is valid, but not part of the specification.

Requirements

A Requirement has an ID, a title, a description, a creation time - the current time, unless given - and a RequirementKind, which names what it constrains: e.g. a function, its performance, a quality, safety or security, an interface, the environment, a design constraint or a regulation. Its Obligation answers whether it is mandatory or optional, by the levels of ISO/IEC/IEEE 29148 and RFC 2119:

Obligation

Keyword

Meaning

Mandatory

shall, must

Binding; the default.

Recommended

should

A goal; a deviation is justified.

Optional

may

A permission.

Its ItemState follows its life cycle from Placeholder over Draft, InReview, Final and Implemented to Verified; a new requirement is a Draft. A verified requirement is Closed, when it is released and changes no more, e.g. in a baseline. At any time, a requirement can be Rejected or become Obsolete.

A requirement belongs to at most one Layer: the requirements of one engineering discipline, e.g. electrical, mechanical, FPGA firmware or software. A layer partitions the requirements; a selection across layers - e.g. the requirements of a product variant - is a Label, or a predicate.

A requirement contains child requirements, which refine it. IterateChildren() iterates the children, IterateDescendants() the children and grandchildren, depth-first. IterateRequirements() iterates every requirement of the specification. Each takes an optional predicate to select the requirements:

from pyTooling.Versioning import SemanticVersion
from pyEDAA.Reports import Person
from pyEDAA.Reports.Requirements import Layer, Requirement, RequirementKind, RequirementSpecification

specification = RequirementSpecification(SemanticVersion(1, 0, 0), "Board")
alice = Person("alice", "Alice", "alice@example.com")
specification.AddPerson(alice)
electrical = Layer("el", "Electrical", parent=specification)

power = Requirement("EL-1", "Power supply", RequirementKind.Functional, layer=electrical, authors=[alice],
                    parent=specification)
Requirement("EL-1.1", "Core rail", RequirementKind.Performance, "0.9 V, 5 A.", layer=electrical, parent=power)

for requirement in specification.IterateRequirements(lambda r: r.Kind is RequirementKind.Performance):
  print(f"{requirement.ID}: {requirement.Title}")

Specification Items

A SpecificationItem mirrors a requirement - with an ID, a title, a state, a layer, persons, personas, labels, documents, child items, links and a history - and states how the system meets requirements, e.g. a design decision or an interface description. Specification items and requirements are in an N:M relation: SpecificationItem.Requirements lists the requirements an item specifies, Requirement.SpecificationItems the items specifying a requirement. SpecificationItem.AddRequirement() maintains both sides. IterateSpecificationItems() iterates every specification item, with an optional predicate.

Verification and Traceability

An item states its Rationale: why a requirement exists, or why a design decision was taken. A requirement names the VerificationMethod flags verifying it - the inspection, analysis, demonstration and test of ISO/IEC/IEEE 29148, plus simulation and formal verification - and its acceptance criteria.

IterateTrace() follows the links of an item transitively, IterateInboundTrace() the inbound links; each item is reached once, also in a cycle. A predicate selects the links followed, e.g. the counterparts of an electrical requirement through the FPGA firmware into the software:

for item in electrical.IterateInboundTrace(lambda link: link.Kind is LinkKind.CounterpartOf):
  print(f"{item.ID} ({item.Layer.Name}): {item.Title}")

History

An item’s History lists the events of its life cycle in chronological order: an event can’t be earlier than the item’s creation or its last event; a time without a time zone is a local time. A HistoryEvent has an EventKind - e.g. opened, modified, approved, split, merged, closed or obsoleted -, a time, optionally the person causing it, and the other items involved: a split names the items a requirement was split into, a merge the items it was merged with.