1 / 36

Refactoring with Contracts

Refactoring with Contracts. Maayan Goldstein School of Computer Science Tel Aviv University. Yishai A. Feldman Efi Arazi School of Computer Science The Interdisciplinary Center Herzliya. Shmuel Tyszberowicz School of Computer Science The Academic College of Tel Aviv Yaffo.

pabla
Download Presentation

Refactoring with Contracts

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Refactoring with Contracts Maayan Goldstein School of Computer Science Tel Aviv University Yishai A. Feldman Efi Arazi School ofComputer Science The Interdisciplinary Center Herzliya Shmuel Tyszberowicz School of Computer Science The Academic College of Tel Aviv Yaffo

  2. Is Software Development a Pain?? • Of course not! It's fun! • But the requirements are always changing… • Dan Berry (2002): • Every development method has a fatal flaw, a pain that developers postpone and avoid • In XP, this is refactoring • For us, it is unit testing!

  3. What Seems to be the Problem? • Writing “all” the necessary tests is hard work • Unit tests need to change with almost any change in the code: • Functionality • Refactoring • Test data generation needed

  4. Solution • Tests should be responsible for exercising the code • The correctness is to be checked by the contract!

  5. Design by Contract • A practical methodology for evolving code together with its specification • Class invariants, method preconditions and postconditions: • Precondition binds clients • Postcondition obliges suppliers • Invariant is a consistency constraint

  6. Behavioral Subtyping (Liskov) • Invariants and postconditions in subclasses • May only be strengthened • Computed as conjunctions (ANDed) • Preconditions in subclasses • May only be weakened • Computed as disjunctions (ORed)

  7. Extreme Design by Contract • Correctness checked by contract • Of course, contract may need to change when code changes… • But Contract expresses intent of code! • Contracts can be refactored systematically • Contract refactoring can be partially automated Crepe == Contract Refactoring Plugin for Eclipse

  8. Agenda • Introduction • Refactoring Examples • Crepe Recipe • Summary

  9. ReadyQueue (1) /** @inv size() >= 0 */ public class ReadyQueue { final private List elements = new LinkedList(); public int size() { /* ... */ } /** @pre job != null * @pre job.status() == Job.READY * @post elements.get(0) == job * @post size() == $prev(size()) + 1 */ public void insert(Job job) { /* ... */ }

  10. ReadyQueue (2) /** @pre size() > 0 * @post size() == $prev(size()) - 1 */ public void remove() { /* ... */ } /** @post (size() == 0) == ($ret == null) */ public Job top() { /* ... */ } }

  11. FreeJobs (1) /** @inv size() >= 0 */ public class FreeJobs { final private List elements = new LinkedList(); public int size() { /* ... */ } /** @pre job != null * @pre job.status() == Job.INACTIVE * @post top() == job * @post size() == $prev(size()) + 1 */ public void insert(Job job) { /* ... */ } READY elements.get(0)== job

  12. @post (size() == 0) == ($ret == null) FreeJobs (2) /** @pre size() > 0 * @post size() == $prev(size()) - 1 */ public void remove() { /* ... */ } /** @pre size() > 0 * @post $ret != null * @post $ret.status() == Job.INACTIVE */ public Job top() { /* ... */ } }

  13. ReadyQueue JobDispenser FreeJobs ReadyQueue FreeJobs Example: Extract Superclass

  14. Extract Superclass Refactoring (1) /** @inv size() >= 0 */ public abstract class JobDispenser { protected List elements = new LinkedList(); /** @pre false * @post size() == 1 + $prev(size()) */ public abstract void insert(Job job); Contradictory preconditions in subclasses: @pre job.status() == Job.READY @pre job.status() == Job.INACTIVE

  15. Extract Superclass Refactoring (2) /** @pre size() > 0 * @post 1 + size() == $prev(size()) */ public abstract void remove(); /** @pre size() > 0 */ public abstract Job top(); public abstract int size(); } Common postconditions (Form slightly changed by theorem-prover) Precondition from FreeJobs, but not from ReadyQueue

  16. Changes: ReadyQueue (1) /** @inv size() >= 0 */ public class ReadyQueue { /** @pre job != null * @pre job.status() == Job.READY * @post elements.get(0) == job * @post size() == $prev(size()) + 1 */ public void insert(Job job) { /* ... */ }

  17. Crepe reasoning: true size() <= 0 size() == 0 Complementsize() > 0from superclass Simplify with invariantsize() >= 0 Changes: ReadyQueue (2) /** @pre size() > 0 * @post size() == $prev(size()) - 1 */ public void remove() { /* ... */ } public int size() { /* ... */ } /** @pre size() == 0 * @post (size() == 0) == ($ret == null) */ public Job top() { /* ... */ } }

  18. Changes: FreeJobs (1) /** @inv size() >= 0 */ public class FreeJobs { /** @pre job != null * @pre job.status() == Job.INACTIVE * @post top() == job * @post size() == $prev(size()) + 1 */ public void insert(Job job) { /* ... */ }

  19. Changes: FreeJobs (2) /** @pre size() > 0 * @post size() == $prev(size()) - 1 */ public void remove() { /* ... */ } /** @pre size() > 0 * @post $ret != null * @post $ret.status() == Job.INACTIVE */ public Job top() { /* ... */ } public int size() { /* ... */ } }

  20. PriorityQueue /** @inv size() >= 0 */ public class PriorityQueue { /** @pre job != null * @pre job.status() == Job.READY * @pre job.priority()< Scheduler.current_priority() * @post size() == $prev(size()) + 1 */ public void insert(Job job) { /* ... */ } // ... }

  21. Example: Add Inheritance ReadyQueue ReadyQueue PriorityQueue PriorityQueue

  22. PriorityQueue vs. ReadyQueue /** @inv size() >= 0 */ public class ReadyQueue { /** @pre job != null * @pre job.status() == Job.READY * @post elements.get(0).equals(job) * @post size() == $prev(size()) + 1 */ public void insert(Job job) { /* ... */ } } /** @inv size() >= 0 */ public class PriorityQueue { /** @pre job != null * @pre job.status() == Job.READY * @pre job.priority()< Scheduler.current_priority() * @post size() == $prev(size()) + 1 */ public void insert(Job job) { /* ... */ } } “Extra” postcondition “Extra” precondition

  23. Add Inheritance • Cannot add inheritance relationship between two classes if, in the subclass, it causes • Preconditions to be strengthened • Invariants or postconditions to be weakened

  24. Add Inheritance (Crepe)

  25. Agenda • Introduction • Refactoring Examples • Crepe Recipe • Summary

  26. The Crepe Recipe • Use Eclipse ASTParser on assertions • Parse the assertions in the Javadoc • Convert to predicate form • Use theorem prover (Mathematica) to verify relationships between assertions • Find contract contradictions • Compute the new contract • Combine existing assertions to create new ones • Compute contracts for arbitrary code (in preparation)

  27. Combining Assertions • Preconditions are conjoined and simplified • Postconditions can be disjoined • But, sometimes the most precise assertions are not best!

  28. class A { /** @post x >= 0 * @post x < 10 * @post y >= 0 * @post y < 10 */ void foo(); } class B { /** @post x >= 10 * @post x < 20 * @post y >= 10 * @post y < 20 */ void foo(); } 20 20 B 10 10 A 10 20 10 20 Extract Superclass - Postconditions

  29. 20 B 10 A 20 B 10 20 10 A 10 20 Postconditions Computation class AB_alternative { /** * @post x >= 0 * @post x < 20 * @post y >= 0 * @post y < 20 */ void foo(); } class AB_strongest { /** @post * (x >= 0 && x < 10 && * y >= 0 && y < 10) || * (x >= 10 && x < 20 && * y >= 10 && y < 20) */ void foo(); }

  30. 20 B 10 10 20 Postconditions Computation class A extends AB_alternative { /** @post x < 10 * @post y < 10 */ void foo(); } class B extendsAB_alternative { /** @post x >= 10 * @post y >= 10 */ void foo(); } 20 10 A 10 20

  31. Agenda • Introduction • Refactoring Examples • Crepe Recipe • Summary

  32. Contracts Refactoring Statistics

  33. Crepe Limitations • Contract computation from arbitrary code • Theorem prover (Mathematica): • Supports only Booleans, Integers, Doubles, and Reals • Fails to simplify some expressions using assumptions • Not open source • Assertions parsing • Return type computations

  34. Summary • Design by Contract is an essential technique for producing high-quality code • It is synergistic with Agile practices • It helps develop with confidence • Automation needed for the process of refactoring with contracts • Crepe demonstrates such automating techniques

  35. Questions?

  36. Thank you!

More Related