Working with Software-Intensive Systems

Revised 24 October 2019

“As a rule, software systems do not work well until they have been used, and have failed repeatedly, in real applications.”
- Dave Parnas

Today, software is ubiquitous in human-developed systems.  Virtually every large system incorporates a substantial amount of software to implement its functions. The classic book on managing projects that involve large amounts of software is The Mythical Man-Month: Essays on Software Engineering by Frederick P. Brooks.  First published in 1975, its insights are as valid today as the day it was written. Many of the thoughts are applicable to other kinds of system development projects as well.

A Systems Perspective on Large Software Projects

  • Large programming projects suffer management problems different in kind from small ones, due to division of labor.
  • Programming projects increase in complexity as they move up the scale in their scope and breadth of application:
    • The movement from a program to a programming product (with generalization, testing, documentation, maintenance).
    • The movement from a program to a programming system (with interfaces, system integration).
      • A programming system is a collection of interacting programs, coordinated in function, disciplined in format.  The assemblage constitutes an entire facility for large tasks.
    • The movement to a programming systems product.
      • The programming systems product is the truly useful object, the intended product of most system programming efforts.
  • Each movement involves a large increment in time, labor, and cost.
  • Test cases in each environment are required that explore the input range and probe the boundaries.
  • The number of test cases needed grows exponentially.
  • Subtle bugs arise from unexpected interactions of debugged components.
  • Programming is unforgiving.  Things must work perfectly. Perfection is mandatory.
  • The programmer depends on other peoples’ programs.  Unfortunately, these are often
    • Mal-designed
    • Poorly implemented
    • Incompletely delivered (no source code or test cases)
    • Poorly documented

Why Can’t It Be Done on the Assigned Schedule?

  • The last bugs take more time to fix than the first.
  • The product is usually obsolete upon (or before) completion.
  • The challenge is to find real solutions to real problems on actual schedules with available resources.
  • Software projects go awry for lack of calendar time.
  • The assumption that men and months are interchangeable is invalid.
  • Software schedule and budget estimating is notoriously bad.
  • Schedule progress is poorly monitored.
  • The fallacious response to schedule slippage is to add manpower.  This just makes matters worse, much worse.
  • Cost varies as the product of the number of men and the number of months.  Progress does not.
  • When a task cannot be partitioned because of sequential constraints, the application of more effort has no effect on the schedule.
    • You cannot get a baby in a month by getting nine women pregnant.
  • The effects of training and intercommunication time are important.
  • Adding more programmers lengthens the schedule.
  • Sequential constraints are especially prominent in component debugging and system test.
  • Testing is usually the most mis-scheduled part of programming.

Planning the Schedule Realistically

  • Brooks’ rule of thumb for scheduling a software task: Allocate
    • 1/3 of the time to planning
    • 1/6 to coding
    • ¼ to component test and early system test
    • ¼ to system test, with all components in hand
  • The planning time does not include research or exploration of totally new techniques.
  • Failure to allow enough time for system test is disastrous.  The delay comes at the end of the schedule, almost at the delivery date.
  • “Take no small slips”.  Allow enough time in the new schedule to do things right.
  • Brooks’ Law: Adding manpower to a late software project makes it later.
  • The number of months of a project depends on its sequential constraints.
  • The maximum number of men depends on the number of independent subtasks
  • The brute force approach is costly, slow, inefficient, and produces systems that are not conceptually integrated.
  • Any programmer who is in code size trouble examines his code to see what he could throw over the fence into a neighbor’s space.

Key Strategies

  • Build the system with as few minds as possible.
  • Recognize there are large individual differences between high and low performers.  Staff the critical functions with high performers.

Focus First on the Top-Level System Design

  • Start from a total system, user-oriented attitude.
  • Insist that a system architect design it all, from the top down.
    • The system architect must confine himself scrupulously to architecture.
  • Conceptual integrity is the most important consideration in system design.
    • Simplicity and straightforwardness proceed from conceptual integrity.
  • The complete and detailed specification of the user interface is especially important.
  • Architecture tells what happens, implementation tells how it is made to happen.
  • The system architects must maintain continual vigilance throughout the implementation to ensure continued system integrity.  They’re not done when the initial design is complete.

The System Specification

  • Refrain from hiring implementers until the specifications are complete.
  • The specification must be done by one or two people, if the consistency of prose and product is to be maintained.
  • One must define what is not prescribed as carefully as what is.
  • Define exactly what a module must do when you specify how big it must be.
  • It is essential to create budgets for the modules—e.g., time to execute.
  • Avoid suboptimization to meet component targets.
  • Every project needs a notebook of good subroutines or macros to use.
  • Redo the representation of the data to get the lean, spare, fast program.
  • Representation is the essence of programming.
  • Before any code is developed, the specification has to be handed to an independent group for scrutinization for completeness and clarity.
  • It is crucial to get the product defined fully.  The problems tend to come from the aspects that were never quite specified.

Management Tools

  • Key documents for project management include:
    • Objectives—need, goals, desiderata, constraints, priorities
    • Specifications
    • Schedule
    • Budget
    • Organization chart
    • Space and time allocations
  • Classic questions to answer include: who, what, when, where, how/how much, and why.
  • You have to have policies written down.  They can’t be implicit.
  • The need for a pilot plant before scaling up to full size is critical.  There is a need to get experience with real world conditions.

Throw Away the First Version

  • Plan in advance to throw the first version away.  You will, anyway.
  • Even the best planning is not so omniscient as to get it right the first time.
  • In most projects, the first system built is barely usable.
  • You have to start again and build a redesigned version in which the problems are solved.
  • Don’t deliver the throwaway to customers!
    • This results in agony for the user
    • Distraction for the programmers doing the redesign
    • Damage to the reputation

Anticipate Change

  • Change is a way of life.
  • Both the actual need and the user’s perception of that need will change as programs are built, tested, and used.
  • As one learns, one changes the design.

Manage Versions

  • Good practices include careful modularization, extensive subroutining, precise and complete definition of intermodule interfaces, and complete documentation of these.
  • Create numbered versions.
  • Each version has a freeze date, after which changes go into the next version.
  • Structuring an organization for change is challenging but essential.
  • Keep controlled copies of the system
    • One locked-up copy of the latest versions, used for component testing
    • One copy under test, with fixes being installed
    • Playpen copies where each programmer can work on his component, doing both fixes and extensions
  • Do careful logging of all changes.
  • Distinguish carefully between quick patches and thought-through, documented fixes.
  • Add one component at a time.

Program Design Control

  • Design programs so as to eliminate or at least illuminate side effects.
  • System bugs often arise from mismatched assumptions made by the authors of various components.
  • Practice the disciplined exorcism of frills of function and flights of technique.

Plan for Program Maintenance

  • The total cost of maintaining a widely used program is typically 40% or more of the cost of developing it.
  • Program maintenance requires far more systems testing per statement written than any other programming.
  • Regression testing is very costly.  You want to make sure the fix hasn’t damaged something else.
  • All repairs tend to destroy the structure and to increase the entropy and disorder of the system.
  • As time passes, the system becomes less and less well-ordered.
  • More and more effort is spent on fixing flaws introduced by earlier fixes.
  • System debugging will take longer than one expects.
  • Maintain tight control during testing.  One person must authorize changes or substitution of one version for another.
  • It is imperative to assume that there will be lots of bugs.

Prevent Schedule Slippage

  • Disastrous schedule slippages usually occur imperceptibly but inexorably.
  • Day-to-day slippages will inevitably happen—snow, jury duty, family problems, emergency meetings with customers, executive audits, etc.
  • You must have a schedule with milestones.  Milestones are concrete, specific, measurable events.
  • Hustle is critical—running faster than necessary, moving sooner than necessary, trying harder than necessary.
  • Hustle provides the cushion, the reserve capacity, which enables a team to cope with routine mishaps, to anticipate and forefend minor calamities.
  • One must get excited about a one-day slip.

Schedule Management

  • There is no substitute for a PERT chart or a critical path schedule.  This shows who waits for what. It shows who is on the critical path, where any slip moves the end date. It also shows how much an activity can slip before it moves into the critical path.
  • Lay out the network, and identify the dependencies.
  • It takes a great deal of very specific planning.
  • You have to replace the first chart with a better one.
  • It shows how hustle is needed to keep one’s own part off the critical path.
  • Sweeping schedule slippages under the rug is a very bad idea.
  • The boss should label meetings, reviews, conferences as status-review meetings versus problem-action meetings, and control himself accordingly.
  • Show milestones and actual completions.
  • The component manager should be prepared to explain why it’s late, when it will be finished, what steps he’s taking, and what help he needs.
  • You want to get accurate, unbiased estimates rather than palatable optimistic estimates or self-protective conservative ones.
  • A plans and controls team is invaluable for a large project.

Documentation of a program should include:

    • Purpose
    • Environment
    • Domain and range
    • Functions realized and algorithms used
    • Input-output formats
    • Operating instructions
    • Options
    • Running time
    • Accuracy and checking
    • Test cases.  These should be small and thorough (e.g., test cases that barely exceed the domain boundary to ensure that invalid inputs result in the correct diagnostic messages)
    • Clear description of a modification

Self-documenting programs are very desirable.


Scroll to Top