Get your own free workspace
View
 

CS221

Page history last edited by Peter Faraday Weller 1 year, 11 months ago


 

Introduction to Software Engineering Lifecycles

 

Software was (and is) in crisis

Two papers; Brooks 1987 (No Silver Bullet) and Gibbs 1994 (Software in Crisis) stated that software development has problems and is currently suffering from a crisis. Gibbs used a number of examples to illustrate the problem:

  • Problems with Denver Airport's automated baggage system
  • For every 6 systems which work, 2 are cancelled
  • For large systems, 3 out of every 4 solutions are reduced in scope or do not work at all

 

Other recent failure examples:

  • Requirements failure: UK Air Traffic Control system - was due to finish in 1998, however it was introduced in 2004 with problems
    • Major problem identified: "Proceeding with system implementation without a robust requirements specification"
    • Additional cost was £180 million
    • "There's never time to build a system properly but there's always time to build it twice"
  • Design failure: Ariane 5 rocket blew up on maiden flight seconds into launch
    • Software failure whilst attempting to convert a 64-bit floating point number to a signed 16-bit integer which caused the number to overflow
    • Diagnostic code was sent to the engines and were interpreted as values, causing the engines to blow up
  • Process failure: CSTARS (Colorado road tax system)
    • After 6 years and $8 million, it stilll didn't work
  • Complexity challenge: Worse electricity blackout ever - affecting much of the US in 2003
    • Error found in 5 million lines of C code
    • Two subroutines wouldn't interact well together under extreme circumstances
  • People problems: Heathrow Terminal 5 
    • Public beta not appropriate for multi-million pound airport terminal 

 

We still have problems today. Software developers are still building systems that both do not work properly and are never used. However, use of the right methods and techniques for software development can significantly improve the quality of software developed. The aim of Brooks' paper was to point out that there is no one solution to solve all the problems, but that the situation can still be improved through a range of methods. This is becoming increasingly important these days as software is being used in more and more dangerous situations - fly by wire, eye surgery, car driving systems and financial systems to name but a few. In light of this, we need to start producing software which is reliable, maintainable, secure, safe, efficient and usable.

 

What is software engineering?

Software engineering can be defined as "the application of science to consistently produce software based systems that are acceptable against the needed criteria (reliability, security, safety, efficiency, usability) in a cost effective way.

 

The IEEE's definition of software engineering is as follows: "The application of a systematic, disciplined, quantifiable approach to development, operation and maintenance of software; that is, the application of engineering to software.

 

What's engineering about?

Other engineering disciples have taught us that it is easy to make an item for your own use (e.g. a bridge over a stream or the Wright brothers' airplane), but it is much harder to engineer a product (e.g. the Severn Bridge or a Boeing 747).

 

To make a product, you must carry out a set of tasks:

  • Find the requirements
  • Design the system
  • Test the system
  • Check production quality
  • Manage the process
  • Maintain the product over time

 

A professional software engineering industry

In the past, gifted amateurs have learned to make software by just doing it, however we cannot continue to do this. We need properly trained individuals in order to develop important systems.

 


 

Software Engineering Models

Whilst some people could argue that there is a "best" way of developing software systems, in reality there are too many different types of software systems (operating systems, productivity systems, control systems, design/analysis systems, embedded software) for a "one size fits all" solution. There are, however, common stages which apply to the development of all software systems.

 

Common stages in software development

  • Requirements Analysis
    • This stage involves establishing what the final product will actually do, including what services it will provide and under what constraints it will be run
  • Design
    • How each of the functions required of the final system will be accomplished
    • Architectural design
      • The overall specification of the system
      • Control structures
      • Data structures
      • Test plans
    • Detailed design
      • Modules
      • Test plans
      • Functional vs. Object-Oriented solution
  • Implementation and testing
    • Writing the code and integrating any necessary hardware
    • Performing unit testing: ensuring that each part/unit of the program performs its task successfully
    • Integration and systems testing: individual units are tested together to ensure that requirements are met
    • Acceptance testing: making sure that the user accepts and can use the system (includes installation and training)
  • Maintenance
    • Longest and most costly phase of the project
    • Making sure a system is easy to maintain can hugely reduce long-term effort and cost

 

Waterfall Model

This was the first explicit model of software development, the first formal description of which is attributed to an article published by Winston W. Royce. 

 

 

The Waterfall Model progresses downwards through all of the phases, with each phase defined not just by the activities which go on in the stage, but by the output as well. Each phase needs to be completed and perfected in order to progress onto the succeeding stage, for which the previous stage is used as the basis. For QA, each stage can be formally verified against the previous stage.

 

The Waterfall Model also has a number of variants (e.g. the V Model, in which the verification phases (i.e. requirements, design, etc) are defined down the left-hand side of the V; the coding phase is defined at the bottom of the V; and the validation phases (i.e. testing) are defined down the right-hand side of the V) and add-ons (such as SSADM and PRINCE/PRINCE2).

 

Advantages

  • Clear and easy to understand
  • Makes the development process visible
  • Makes planning/management/system-building easier
  • Late changes are less likely to affect the overall design

 

Disadvantages

  • Not very flexible
  • Makes it hard to respond to changes
  • You're less likely to build what the user wants
  • Stages often overlap with each other

 

When used in reality, work on subsequent phases are often required before the phase a developer is working on can be completed, and problems in later stages often need reworking of previous stages. As well as this, the user's perceived requirements may well change during the software development process. Prototypes may also be developed, which can allowthe use of incremental development techniques - each increment being a different release.

 

A different development model should be used when more flexibility is required (at the expense of control), and especially in cases where requirements are either not clear or changing rapidly/regularly.

 

Evolutionary Prototyping

Evolutionary prototyping (which is also known as breadboard prototyping), makes up a part of a software development methodology. Whilst using it, the system is gradually evolved by constantly refining a robust prototype.

 

Evolutionary prototyping is generally only used when it's difficult to describe exactly what the system is required to do or if it's not clear what the solution will look like (i.e. in order to implement design features which could not be conceived in the design process). While incremental prototyping is often used as a part of a larger development model, it generally not to be used by itself.

 

While prototypes are often robust enough to be used in the interim, prototypes should generally be refactored to produce the final product, feeding back ideas and experience into the next release.

 

Incremental Development

Incremental development involves building the system in parts, providing multiple deliverables of the system, allowing the developer(s) to take advantage of knowledge learned from previous iterations.

 

 

This software development methodology was developed in response to the weaknesses of the Waterfall Model. Whilst starting with initial planning and ending with deployment (as in the Waterfall Model), a cyclic model is used in between in order to deliver increments of the system.

 

Incremental development is often used in practice, especially on smaller projects (as the development team is often not quite big enough to work on all the functionality at once). It's only really a cyclic variation of the Waterfall Model.

 

Advantages

  • Encourages extra milestones
  • Avoids crises by alerting the development team to (potential) problems earlier on in the development process
  • Gets user feedback sooner

 

Disadvantages

  • Doesn't work for all systems
    • Some systems may require all the units to be implemented before integrated testing can take place
  • A good design and understanding of modular dependencies is needed for it to work well

 

Boehm's Spiral Model

A development model first described by Boehm's 1988 article "A Spiral Model of Software Development and Enhancement" which combines concepts from prototype-based development models and waterfall-based development models. 

 

 

There are are a number of steps which make up the spiral model:

  1. Define the new system requirements in as much detail as possible (usually by interviewing users)
  2. Create a preliminary design. If there are any risks which indicate any kind of uncertainty in the system, prototyping may be used with the existing data to find a solution to deal with any potential changes in the requirement.
  3. The first prototype is created, it is generally a scaled-down version used to illustrate the approximate characteristics of the final software.
  4. A four-step procedure is used to develop the next prototype:
    1. Evaluate the first prototype
    2. Define the requirements of the second prototype
    3. Plan and design the second prototype
    4. Construct and test the second prototype

 

Advantages

  • Follows a systematic approach
  • Has risk-reduction "features"
  • Supports iteration
  • Follows real-world practices

 

Disadvantages

  • Requires expertise in risk-reduction
  • Complex and relatively difficult to adhere to strictly

 

The spiral model is used extensively in game development as they often have large size and goals which have not been set in stone. It is not really suited, however, for large complicated distributed systems.

 

Extreme Programming

One of the latest processes for developing software; encourages frequent releases and is an example of Agile software development.

 

 

Frequent releases in short development cycles is used in an attempt to help increase productivity and to introduce checkpoints for the introduction of new features. Extreme programming also advocates pair programming, extensive code review, unit tests for all elements of the code, "simple" code (i.e. make the simplest choice, then refactor if needs be) and involving the customer.

 

Advantages

  • Clear process
  • Makes the development process visible
  • Allows for late design changes
  • Very flexible

 

Disadvantages

  • Imposes potentially unfamiliar disciplines
  • May not be able to grow the design incrementally
  • One user may not represent the entire userbase
  • Not appropriate for very large systems
  • May not be good for long-term maintenance

 

Model-Driven Architecture (MDA)

With MDA (launched in 2001 by the Object Management Group (OMG)), the developer models the software system with abstract human-readable modelling diagrams before producing code from it.

 

A Platform Independent Model (PIM) is used to define a system's functionality using a domain-specific language (DSL), after which it is translated to a Platform Specific Model (PSM) using a Platform Definition Model (PDM).

 

The OMG does not provide any implementations, rather, they create rough specifications. It is up to private companies and/or open source groups to provide implementations.

 

Advantages

  • Extremely high level
  • Concentrates on what's important
  • Emphasises reuse
  • Could replace prototyping
  • Documentation matches code (however, code is no longer important)

 

Disadvantages

  • Not working for general usecases
  • De-emphasises the user interface
  • Overkill for most projects

 


 

Software Testing

Testing is used not just to see if your program works, but primarily to try and make your program break and find bugs, especially in extreme situations (which may well be uncommon, but can happen).

 

Testing Driven Development (TDD)

TDD is fairly new, but extremely useful - even more so now that there are many more automated testing tools. In TDD, tests are defined and implemented before coding begins. This helps to ensure that you understand what you're coding (i.e. what should be happening), ensures that you can test to make sure you've achieved what you aimed to do and check that code still does what it should do whilst making changes.

 

Levels of testing

There are a number of different levels of testing, some levels of which may or may not be relevant to your system. The levels of testing required for your system should be identified whilst planning the project.

 

Unit testing

Used to test each unit/module of code (i.e. a module or a class) in isolation.

 

Integration testing

Testing related units of code together to ensure that they work happily with each other.

 

System testing

Putting together tested subsystems to complete the system and testing the entire system against the specification.

 

Acceptance testing

Testing by the users or customers to ensure that the project satisfies their needs.

 

When testing should be done (and who by)

Unit testing is done whilst building the system; integration and system testing are done towards the end of a release cycle. When a unit is changed, integration and system testing should be repeated to ensure that there are no new bugs present in the system. The exact same tests need to be done repeatedly in order to ensure that there are no regressions; automation makes less work. Unit testing should be performed by the developer, whereas integration and system testing should be done by a testing team.

 

Test Plans

The test plan is extremely important for overall QA - it is subjected to QA itself. It contains two main parts (the strategy and principles, as well as detailed test specifications, including expected results), and producing a test plan can consume a lot of resources. The test plan strategy should contain the following:

  • Levels of testing and order of testing
  • Time schedule of tests
  • Software/hardware environment for tests
  • Where tests and results will be stored
  • Which tools will be used
  • Who says whether or not a test has been carried out
  • Comprehensiveness
  • How the results should be recorded

 

What to test for

Test should check for correct behaviour for every functional requirement of the system. A developer should try to think of everything which could go wrong with a system and try and make it happen.

 

Inputs and outputs

  • Inputs which force all errors on erroneous inputs
  • Default inputs
  • Characters such as "\n" which could be (mis)interpreted by the program
  • Illegal combinations of data
  • Overflow input buffers
  • Force screen refreshes

 

Wrong data storage/computation

  • Try changing to invalid values
  • Linked computations
  • Explore boundaries
  • Force results to be too large/too small
  • See whether page sizes can be restored

 

Operating system interaction

  • Full discs
  • Incorrect file permissions
  • Out of RAM
  • No network response
  • Corrupt file structures
  • Multi-user systems
    • Test with more users than expected

 

Most of the same principles also apply to unit testing.

 

Tools to help with testing

There are a number of tools available to help aid testing, some of which will be explored here.

 

Static analysers

Static analysers are used to analyse possible paths through a program in order to detect suspicious circumstances (e.g. unused variables, uninitialised variables, code which can never be reached). These checks are generally carried out by the compiler (indeed, if you use an IDE such as Eclipse, warnings will be shown whilst writing the code).

 

Dynamic analysers

Dynamic analysers keep records of the running of a program, including which statements have been executed and how many times. It's useful for checking test coverage (i.e. making sure each statement has been executed in order to be tested). It's also used when tuning the program for performance - working out where the program slows down, allowing the developer to concentrate on making those parts faster.

 

Test data generators

Large quantities of test data are often required for many system. Test data generators take a description of the data required and generates random data according to this format. Special-purpose test generators are often written specifically for large projects/systems.

 

Simulators

Simulators are often used to test large real time projects as many bugs are timing-dependant and so are difficult to reproduce. These simulators can often be run for hours or days.

 

File comparators

File comparators checks for differences between two files. They are often useful when the test output of a program is in the format of a large file, and they can be used for regression testing.

 

Test running utilities

Programs are often used to assist in running tests; examples include shell scripts and JUnit testing. JUnit testing is an extremely useful tool in Java, test classes contain code to set up the test situation, define the test methods and assert what the result of each test should be.

 

User interface testers

These are special case test tools - it's extremely difficult to test all aspects of a user interface. Interface test tools are often used to remember where users click and reproduce it; and to remember what a user clicks on.

 


 

Requirements Analysis

"Fixing an error will probably be 10 to 100 times more expensive than fixing a coding error". Requirements analysis is the process of defining the problem which needs to be solved and the constraints within which one must work. It provides a basis for the design specification by defining the end product. In addition, this also provides a basis for the tests to ensure that we have built the right thing.

 

Unfortunately, requirements analysis is often ignored or done badly. It is very hard, so people often go on to "easier" tasks such as designing (or even worse, straight into coding). In order to complete a requirements analysis, the right questions need to be asked; the development team need to understand the problem, have or gain experience of the system and to follow a guideline of things to cover.

 

In order to decide on the requirements, an overview of the system is needed to set the context and various different requirements need to be defined (this covers both functional requirements (i.e. services, facilities, options, reports, alarms, etc) and non-functional requirements (i.e. constraints (size, speed, type of hardware), how it must be developed, legislation, etc, etc).

 

Specifying requirements

Requirements can be specified in a number of ways:

  • Numbered
    • According to type
      • Functional
      • External interface
      • Performance
      • Design constraints
      • Others
  • Named
    • Short summary of what the requirement covers
  • Single requirement for each number (hard to evaluate)

 

Requirements must obey the following rules:

  • Readable and understandable; need to communicate with:
    • Management (of your company or the client)
    • Designers/coders/testers
    • QA
  • Unambiguous
    • Difficult with natural language but needed
  • Complete
    • All major functions
    • Point out any items to be decided
  • Verifiable
    • Tests
  • Consistent
    • Different requirements shouldn't conflict
    • Helps if you avoid redundancy
    • Lack of consistency can be due to ambiguous language
  • Maintainable
    • Specification must be organised
    • Numbering/naming helps keep track of requirements

 

Specifying requirements is often troublesome because the user's understanding is often incomplete and their viewpoint irrational and inconsistent. It is difficult to get "real" requirements from the user. The user also often thinks of shiny new things they want, which doesn't help at all.

 


 

Software Maintenance

The process of changing a software system after it is in use. Software maintenance typically makes up 50-70% of the effort involved in the lifecycle of commercial software.

 

Types of Maintenance

Corrective Maintenance

  • Diagnosis and correction of errors

 

Adaptive Maintenance

  • Modification of software because of environmental changes

 

Perfective Maintenanced

  • Adding extra functionality and improving functionality

 

Preventive Maintenance 

  • Defensive rewriting of the code
  • Refactoring

 

Cost of Maintenance

The costs of adding functionality to software once it is in use is usually much greater than the cost of implementing similar functionality when the system was first developed. This is due to a number of reasons:

  • Inexperienced staff
  • Code developed without the use of modern software engineering techniques
  • Changes may introduce new faults
  • Degradation of structure
  • Links between program and associated documentation are sometimes lost

 

How can you reduce the cost?

  • Keep the design simple and take into account likely changes
  • Good documentation which is kept up to date
    • Requirements specification
    • Design documents
    • Maintenance guide
      • Rebuilding information (code, test and batch file locations)
      • Examples of potential changes
      • Thoughts on path of evolution
      • Error codes
      • Proper design information
  • Using proper tools in order to do the above
    • JavaDoc
    • ANT
    • JUnit
  • Regression tests to ensure that changes don't make things worse
  • Refactoring

 

The Maintenance Process

  1. Change request filed
  2. Evaluation of request
    • Not a problem
    • Not our problem
    • Our problem - no action
    • Our problem - no action until future release
    • Our problem - action now
  3. If action is required, assign resources to the change request
  4. Implement change request and add new tests
  5. Update the documentation
  6. Make a new release

 

 

Code Refactoring

Techniques used to reduce the short-term pain of redesigning software to make it easier to maintain. You do not need to change what the program does - you only change the program's internal structure to make it more logical and easier to understand and work with.

 

Code refactoring often involves small steps:

  • Renaming methods
  • Moving fields from one class to another
  • Consolidating two similar classes into one superclass

These small steps can often make a huge amount of difference to a program in a short amount of time.

 

Refactoring code is often not a natural inclination when maintaining software, but it can save you lots of time and grief in the long run.

 

When and how code should be refactored

When?

  • When you can no longer work out what the code does
  • When your code smells bad

 

How?

  • Don't refactor and upgrade functionality
  • Make sure you have good tests and use them
  • Refactor the code in small steps and test each change 

 

Bad Smells in coding

  • Duplicated code
  • Very large class(es)
    • Is there too much in a single class?
    • Is too much of it conditional?
  • Long methods
    • Is it more than 10 lines of functionality?
    • Is it trying to do more than one thing?
  • Switch statements
    • Often implies bad use of Object-Oriented Programming
    • Switch is prone to errors of accidental fallthrough
  • Bad comments
    • Comments shouldn't duplicate code
    • Methods/classes should have short comments to describe their functionality