280 likes | 442 Vues
Specifications Liskov Chapter 9. SWE 619 Last Updated Fall 2008. Overview/Agenda. Review why we use specifications as a software construction tool? Restating the reasons from chapter 1 How to write good specs (for desired behavior)? Advice from Liskov Some formal ways to specify behavior
E N D
SpecificationsLiskov Chapter 9 SWE 619 Last Updated Fall 2008
Overview/Agenda • Review why we use specifications as a software construction tool? • Restating the reasons from chapter 1 • How to write good specs (for desired behavior)? • Advice from Liskov • Some formal ways to specify behavior • Z, OCL (SWE 623)
Why Specifications? • What do specifications do? • Who is the target audience? • How are they constructed? • What is their use? • Do they evolve?
Construction • Intended for: designers, implementers, testers, maintenance people, clients • In short: intended for people [users] • How formal can specifications be? • Must clearly state what the must the software do • Can informal specs be clear? • Must be understood by users of the specification.
Use • Implementers: understand system requirements, tasks to be performed • Testers: Understand functional requirements • Clients: understand how to use the software
Understanding abstractions • What must be understood? • Behavior of some abstraction • How to specify behavior? • abstract state, changes to abstract state • abstract descriptions • Leads to multiple implementations that satisfy an abstraction • Satisfy? Implementations follow contract i.e., pre and post conditions
Meaning of an abstraction • The set of implementations that satisfy an abstraction is the specificand set. • Specificand set is the meaning of an abstraction • Example public int 3DigitNumber() //E: return an integer greater than 99 // and less than 1000 What is the meaning of this abstraction?
Liskov example static int p (int y) // R: y > 0 // E: returns x such that x > y Specificand set: (possible implementations) {return y + 1;}, { return y + k ;} (k > 0) {return y * 2;}, {return y * k ; } (k > 1) {return 4y – 2;} What about {return 4y – 3;} ?
Liskov example (contd.) static int p (int y) // R: true // E: returns x such that x > y • What does strengthening/weakening of pre/post conditions do to the specificand set? • weakening pre smaller specificand set • New set is a subset of old set • strengthening post smaller specificand set • Again, new set is a subset of old set
Specs for desired behavior • Note that “desired” differs from “correct” • Specs determine specificand set • Do all members of specificand set exhibit desired behavior? • Throw out implementations that do not • Are there missing members of specificant set? • Add implementations that are missing
Sufficiently restrictive specs • Rephrase specs prune specificand set • Example: Iterator for a (mutable) bag bag = [Book, Book, Pen, Pencil] //E: returns every element in bag • Type of implementations for this spec? • Duplicates? • Elements not in bag? • What about order? • What about mutability?
Refining specs for desired behavior • If do not desire duplicates (i.e. Pen once, Book once): // E: returns all unique elements in bag only once • If order matters: // E: returns elements in order they were put in the bag (FIFO) • If mutability matters: // R: No change to bag while iterator in use // E: returns every element in bag
Refining specs for desired behavior (contd.) • If mutability matters: //E: returns every element in bag, throws // CME if iterator modified while in use • If only elements in bag desired: //E: returns only the elements in bag
Sufficiently general specs • Apparent contradiction with the earlier goal of pruning specs! • What if the specs are over specified? • i.e., some valid and desired implementations are not the members of the specificand set • Over specifications are bad in the sense that some desired implementations are lost
Classic over specification e.g. Consider a container with method: public Object getElement() • Desire any one element from the container • Spec: //E: returns 3rd element in the container • Obviously over-constrained.
Generality of specs • Specifications come in 2 flavors • Operational: A recipe or algorithm • Definitional: Some property or constraints that inputs/outputs satisfy • Prefer definitional specs • More freedom to implementer regarding choice of algorithm • But not a natural choice for most students
Clarity • Every user of the spec should have the same interpretation of the spec! • Possible if we allow formal specs • Not easy to understand formal specs! • Clear, unambiguous specifications are hard to get • Expect to make mistakes! • What to do? • Allow redundancy in specs
Redundancy • Specs are not concise • Easier to understand • 2 flavors • i.e. redundant definition • e.g. provide an example • Reduces chances of missing an important point
Liskov example static boolean subset (Set s1, Set s2) throws NPE // E: if s1 or s2 is null, throws NPE else returns true // if s1 is a subset of s2, else returns false • Makes sense to every reader • What could be wrong here?
Example contd. • What if s1 equals s2? • Design decision about what to return for improper subset. • Rephrasing specs as: //E: … NPE else, returns true if every element of s1 is an element of s2, else false • Is this a better spec?
Example continued • Second spec allows improper subset • Eliminates ambiguity. • But why not use accepted terms? • Liskov: don’t replace, include both! //E: …NPE, returns true if s1 is a subset of s2, i.e., returns true if every element of s1 is an element of s2, else false
Alternate spec • Still better way to make sense to a wide variety of audience is to add more redundancy (without being repetitive) // E: … NPE, returns true if s1 is a subset of s2, i.e., returns true if every element of s1 is an element of s2, else false, e.g., subset({7}, {3, 7}) returns true, subset({3}, {7}) returns false, subset ({7}, {7}) returns true
How much effort into specs? • Avoid verbosity, repetitiveness but not compromise on clarity • Examples are powerful as specifiers, good idea to include them • Only a handful of examples can help you think about restrictive and general specs
Test Driven Development as a Specification Exercise Basic idea: Define tests first Then develop code to satisfy tests Lots of process stuff as well Connection to current lecture: Specification examples are tests Specification examples greatly help specifier understand abstraction Rule of thumb: Most development artifacts are more useful if they are executable 24
Formal specifications • Specifications/ Analysis in Z (Zed) • Occasionally taught in SWE 623 • Basis for OCL in UML
Specification in Z • Scenario: We maintain a membership list and an associated phone database. [Person, Phone] |----PhoneDB----------------------------------- |members: P Person (‘set of’ person) |phones : Person Phone (relation) |------------------------------------------------------- |dom phones ⊆ members (invariant) |---------------------------------------------------
Z Operation: Assign a Phone • Scenario: Someone would like a phone. (Note: Missing precondition) |----Assign----------------------------------- | p? : Person; n? : Phone | PhoneDB |------------------------------------------------------- | phone’ = phone { p? n? } | members’ = members |---------------------------------------------------
Example • members {jim, sue} • phones {(jim, 1231), (sue, 3956)} • Assign(alice, 1231) • Cool Z property: Can calculate minimal preconditions!! • Simple analysis: leave out preconditions and find minimum constraint to maintain invariants!