Goals of Software Design: Design Faces Many Challenges To Produce A Good Product, E.G. Shifting Requirements
The document discusses the goals of software design, which include producing software that is correct, robust, flexible, reusable, efficient, reliable, and usable. It defines these terms and provides examples of how each goal can be achieved through good design practices like encapsulation, abstraction, and modularity. It also discusses different approaches to verifying that software meets its requirements, such as testing, formal verification, and code inspections.
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0 ratings0% found this document useful (0 votes)
37 views
Goals of Software Design: Design Faces Many Challenges To Produce A Good Product, E.G. Shifting Requirements
The document discusses the goals of software design, which include producing software that is correct, robust, flexible, reusable, efficient, reliable, and usable. It defines these terms and provides examples of how each goal can be achieved through good design practices like encapsulation, abstraction, and modularity. It also discusses different approaches to verifying that software meets its requirements, such as testing, formal verification, and code inspections.
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 51
7.
Goals of Software Design
Design faces many challenges to produce a good product, e.g. shifting requirements. But what do we mean by good ? We need some clear goals here Good design leads to software that is: 1. Correct does what it should 2. Robust tolerant of misuse, e.g. faulty data 3. Flexible adaptable to shifting requirements 4. Reusable cut production costs for code 5. Efficient good use of processor and memory Also should be Reliable and Usable 7.1. Correctness Software is correct, if it satisfies its requirements. A primary goal, incorrect software may look good, but will be poor or worse. Requirements are divided into functional (what it does) and non-functional (how it does it, etc.) Non-functional Product Organisational External Product Efficiency Reliability Portability Usability Speed Throughput Memory Organisational Delivery Implementation Standards e.g. ISO 9000 e.g. quality of documentation, manuals, training, support e.g. commenting, flexibility, openess, maintainability External Legislative Interoperability Ethical Privacy Safety Commercial See later in the course e.g. licensing Requirements may be expressed in Text f() computes a square root function also, text use cases. Logic Tol | f(x) 2 x | (see also UML Object Constraint Language) Diagrams output should look like this UML Sequence Diagrams system should behave like this Many functional requirements can be expressed in terms of a precondition e.g. if the input is a positive integer and a postcondition e.g. the output will be the square root of the input. { in 0 } system {Tol | out 2 in | } 7.1.1. Verification Checking software against its requirements is called verification. Three main approaches: 1. Testing, 2. Formal Verification 3. Code Inspections Testing takes a contrarian approach, falsify correctness claim by finding a counterexample to correctness, i.e. a test case that fails, Thus precondition is true, but postcondition is false. Testing can only uncover errors, it can never prove a system is correct. Formal verification takes a mathematical approach: Step 1: model the code mathematically, Step 2: model the requirement mathematically Step 3: prove code satisfies requirement Important approach to safety critical systems: medical, avionics, automobile, nuclear power, financial systems, smart cards, etc. Code Inspection is a manual process of code walk-through (discussion). Usually done in front of a group or team. Not mathematical, but more systematic than testing. Has been empirically shown to be more cost effective than manual testing bugs found per dollar. But testing and formal verification getting cheaper through automation. 7.2. Robustness A design or system is robust if it tolerates misuse without catastrophic failure. aka. fault-tolerant. Includes bad data, bad use, bad environment, bad programming. Robustness achieved in many ways: Use data abstraction and encapsulation CreateADTsand simple interfaces Shield from data corruption Initialize variables Qualify all inputs (e.g. range check) Same as precondition checking Qualify all formal parameters to a method Qualify invariants (e.g. non-null pointer, not end_of_file ) Qualify postconditions 7.3. Flexibility Requirements may change during or after the project. Obtaining more of whats present e.g. more kinds of different bank accounts Adding new kinds of functionality e.g. add internet banking to teller functionality Changing functionality e.g. allow withdrawals to create an overdraft Flexibility achieved in many ways: Encapsulation (representation hiding) Different types of the same base category by means of abstract classes Extend functionality by new class methods or with an abstract class & several derived classes. 7.4. Reusability Aim: cut cost of code production over 1 or more projects. Reuse object code (see later discussion of component technologies) Reuse source code see next slides Reuse assemblies of related classes, e.g. software frameworks Reuse patterns of designs see previous! 7.4.1. Promoting Source Code Reuse Use modularity Use classes and interfaces which are independent and as general or specific as necessary Use Classes Describe class with good name& documentation Minimize dependencybetween classes Maximally abstract and general or precisely matchedto real objects and their function 7.4.1. Continued Write good methods Explain the algorithm Use good names Specify pre + postconditions+ invariants Dont couple closely to class 7.5. Efficiency Aim: Make greatest use of the processing power, memory size, network speed, etc. But all these things are getting cheaper! But applications are getting bigger! Efficiency is often against the first 4 goals! Efficiency is often achieved by writing clever algorithms and data structures. Needs a good education in this area. Efficiency can also be obtained by profiling code search for execution intensive code sections with code profiler, try to optimize these. Sometimes write low level routines, e.g. assembler. Use an optimizing compiler. Use a J ava compiler throw away portability. 7.6. Reliability & Usability Reliability mean time to failure (system crash, error) On architectural level can use hardware support, backup servers, multiple processors, hot swap, etc On code level achieved by software quality assurance methods, testing, walkthroughs, formal methods etc. Usability users must find software easy to easy. Intuitive GUI, standard layout & meanings Good documentation, Well known use metaphor desktop, calculator, tape recorder, etc. Connections to ergonomics & cognitive psychology Hard to define and measure, user interviews, questionnaires, etc. 8. Testing Defines program functionality (partly) Can be used as documentation (c.f. XP!) Ensure program is testable Methods become callable Modules get a looser coupling If written first, then we avoid risk of testing code we know works instead of code which should work. Coding (Phase) Detailed Design Glass & Black Box Unit Testing Architectural Design System Testing Software Requirements Integration Testing User Requirements Acceptance Testing Time 8.1. The V Model : Workflow D e s i g n
P h a s e T e s t
P h a s e 8.2. Types of Testing 8.2.1. Unit Testing Tests a basic component, module Glass box/structural test path analysis Coverage measures 8.2.2. Regression Testing Does new functionality disturb existing functionality? Keep old test suite + old results rerun. 8.2.3. System testing Black-box testing, structure of code is invisible Test the specification, not the code! Hard to find the tests oracle problem Hard to define coverage Volume of testing, usage profiles? Use cases are an excellent source of tests. UseCaseName PurchaseTicket Precondition The Passenger is standing in front of ticket Distributor and has sufficient money to purchase ticket. Sequence 1. The Passenger selects the number of zones to be traveled. If the Passenger presses multiple zone buttons, only the last Button pressed is considered by the Distributor. 2. The Distributor displays the amount due. 3. The Passenger inserts money. 4. If the Passenger selects a new zone before inserting sufficient money, the Distributor returns all the coins and bills inserted by the Passenger. 5. If the Passenger inserted more money than the amount due, the Distributor returns excess change. 6. The Distributor issues ticket 7. The Passenger picks up the change and the ticket. TestCaseName PurchaseTicket_SunnyCase Precondition The Passenger is standing in front of ticket Distributor and has two 5 notes and 3 * 10p coins Sequence 1. The Passenger presses in succession the zone buttons 2, 4, 1, and 2. 2. The Distributor should display in succession 1.25, 2.25, 0.75 and 1.25 3. The Passenger inserts a 5 note. 4. The Distributor returns three 1 coins 75 and a 2-zone ticket. Postcondition The Passenger has one 2-zone ticket. We should also derive test cases from the use case that exercise rainy day scenarios (when something goes wrong). 8.2.4. Acceptance Testing On-site by the customer Tests come from requirements document Legal/contractual consequences Affected by the real environment. 8.3. Unit Testing with JUnit Developed by XP community 2002 Framework for automating the execution of unit tests for J ava classes. Write new test cases by subclassing the TestCase class. Organise TestCases into TestSuites. Automates testing process Built around Commandand Composite patterns 8.3.1. Why Use JUnit? J Unit tightly integrates development and testing, supports the XP approach Allows you to write code faster while increasing quality (!!!) Can refactor code without worrying about correctness. J Unit is simple Easy as running the compiler on your code. J Unit tests check their own results and provide immediate feedback. No manual comparison of expected with actual Simple visual feedback J Unit tests can be composed into a hierarchy of test suites. Can run tests for any layer in hierarchy Writing J Unit tests is inexpensive No harder than writing a method to exercise the code. J Unit tests increase stability of software More tests = more stability J Unit tests are developer tests Test fundamental building blocks of system Tests delivered with code as a certified package J Unit tests are written in Java Seamless bond between test and code under test Test code can be refactored into software code and vice-versa Data type compatibility (floats etc) J Unit is free! 8.3.2. JUnit Design A TestCase is a Commandobject. A class of test methods subclasses TestCase A TestCase has public testXXX() methods To check expected with actual output invoke assert() method Use setUp() and tearDown() to prevent side effects between subsequent testXXX() calls. Test run(TestResult) TestCase run(TestResult) setUp() tearDown() runTest() testName:String ConcreteTestCase setUp() tearDown() runTest() TestSuite addTest() run(TestResult) TestResult TestCase objects can be composed into TestSuite hierarchies. Automatically invoke all the testXXX() methods in each object. A TestSuite is composed of TestCase instances or other TestSuite instances. Nest to arbitrary depth Run whole TestSuite with a single pass/fail result. See course web page for installation instructions. 8.3.3. Writing a Test Case 1. Define a subclass of TestCase 2. Override the setUp() method to initialize object(s) under test. 3. Optionally override the tearDown() method to release objects under test. 4. Define 1 or more public testXXX() methods that exercise the object(s) under test and assert expected results. import junit.framework.TestCase; public class ShoppingCartTest extends TestCase { privateShoppingCart cart; private Product book1; protected void setUp() { cart = new ShoppingCart(); book1 = new Product ( myTitle , 500SEK ); cart.addItem(book1); } protected void tearDown() { // release objects under test here, if necessary } public void testEmpty() { cart.empty(); assertEquals(0, cart.getItemCount() ); } public void testAddItem() { product book2 = new Product( title2 650SEK ); cart.addItem(book2); double expectedBalance = book1.getPrice() + book2.getPrice(); assertEquals(expectedBalance, cart.getBalance(), 0.0); assertEquals(2, cart.getItemCount() ); } public void testRemoveItem() throws productNotFoundException { cart.removeItem(book1); assertEquals(0, cart.getItemCount() ); } public void testRemoveItemNotInCart() { try { Product book3 = new Product( title3 , 100SEK ); cart.removeItem(book3); fail( Should raise a ProductNotFoundException ); } catch(ProductNotFoundException expected) { // passed the test! } } } // of class ShoppingCartTest 8.3.4. Writing a Test Suite 1. Write a J ava class that defines a static suite() factorymethod that creates a TestSuite containing all the tests. 2. Optionally define a main() method that runs the TestSuite in batch mode. import junit.framework.Test; import junit.framework.TestSuite; public class EcommerceTestSuite{ public static Test suite() { TestSuite suite = new TestSuite(); // Add one test case suite.addTestSuite(ShoppingCartTest.class); // Add a suite of test cases suite.addTest(CreditCardTestSuite.suite()); return suite; } public static void main(String[ ] args) { junit.textui.TestRunner.run(suite( ) ); } } 8.3.5. Running Tests Running a TestCase runs all its public testXXX() methods Running a TestSuite runs all its TestCases and subordinate TestSuites. Text user interface java junit.textui.TestRunner ShoppingCartTest Graphical user interface java junit.swingui.TestRunner EcommerceTestSuite 8.3.6. Graphical User Interface 8.3.7. Testing Idioms Software does well what tests check Test a little, code a little, test a little , Run all tests at least once a day Write tests for areas of code with highest probability of error Write unit tests before writing the code and only write new code when a test is failing.