You are previewing Code Quality.
O'Reilly logo
Code Quality

Book Description

Diomidis Spinellis' first book, Code Reading, showed programmers how to understand and modify key functional properties of software. Code Quality focuses on non-functional properties, demonstrating how to meet such critical requirements as reliability, security, portability, and maintainability, as well as efficiency in time and space.

Spinellis draws on hundreds of examples from open source projects--such as the Apache web and application servers, the BSD Unix systems, and the HSQLDB Java database--to illustrate concepts and techniques that every professional software developer will be able to appreciate and apply immediately.

Complete files for the open source code illustrated in this book are available online at: http://www.spinellis.gr/codequality/



Table of Contents

  1. Copyright
    1. Dedication
  2. Effective Software Development Series: Scott Meyers, Consulting Editor
    1. Titles in the Series
  3. List of Tables
  4. List of Figures
  5. Foreword
  6. Preface
    1. Content and Supplementary Material
    2. Acknowledgments
  7. 1. Introduction
    1. 1.1. Software Quality
      1. 1.1.1. Quality Through the Eyes of the User, the Builder, and the Manager
      2. 1.1.2. Quality Attributes
      3. 1.1.3. A World of Tensions
    2. 1.2. How to Read This Book
      1. 1.2.1. Typographical Conventions
      2. 1.2.2. Diagrams
      3. 1.2.3. Charts
      4. 1.2.4. Assembly Code
      5. 1.2.5. Exercises
      6. 1.2.6. Supplementary Material
      7. 1.2.7. Tools
    3. Further Reading
  8. 2. Reliability
    1. 2.1. Input Problems
    2. 2.2. Output Problems
      1. 2.2.1. Incomplete or Missing Output
      2. 2.2.2. Correct Results at the Wrong Time
      3. 2.2.3. Wrong Format
    3. 2.3. Logic Problems
      1. 2.3.1. Off-by-One Errors and Loop Iterations
      2. 2.3.2. Neglected Extreme Conditions
      3. 2.3.3. Forgotten Cases, Condition Tests, or Steps
      4. 2.3.4. Missing Methods
      5. 2.3.5. Unnecessary Functionality
      6. 2.3.6. Misinterpretation
    4. 2.4. Computation Problems
      1. 2.4.1. Incorrect Algorithm or Computation
      2. 2.4.2. Incorrect Operand in an Expression
        1. Uninitialized Variables
        2. Dereferencing NULL
        3. Using Concrete Types
        4. Abusing the Type System
      3. 2.4.3. Incorrect Operator in an Expression
      4. 2.4.4. Operator Precedence Problems
      5. 2.4.5. Overflow, Underflow, and Sign Conversion-Errors
    5. 2.5. Concurrency and Timing Problems
    6. 2.6. Interface Problems
      1. 2.6.1. Incorrect Routine or Arguments
      2. 2.6.2. Failure to Test a Return Value
      3. 2.6.3. Missing Error Detection or Recovery
      4. 2.6.4. Resource Leaks
      5. 2.6.5. Misuse of Object-Oriented Facilities
    7. 2.7. Data-Handling Problems
      1. 2.7.1. Incorrect Data Initialization
      2. 2.7.2. Referencing the Wrong Data Variable
      3. 2.7.3. Out-of-Bounds References
      4. 2.7.4. Incorrect Subscripting
      5. 2.7.5. Incorrect Scaling or Data Units
      6. 2.7.6. Incorrect Data Packing or Unpacking
      7. 2.7.7. Inconsistent Data
    8. 2.8. Fault Tolerance
      1. 2.8.1. Management Strategy
      2. 2.8.2. Redundancy in Space
      3. 2.8.3. Redundancy in Time
      4. 2.8.4. Recoverability
    9. Advice to Take Home
    10. Further Reading
  9. 3. Security
    1. 3.1. Vulnerable Code
    2. 3.2. The Buffer Overflow
    3. 3.3. Race Conditions
    4. 3.4. Problematic APIs
      1. 3.4.1. Functions Susceptible to Buffer Overflows
      2. 3.4.2. Format String Vulnerabilities
      3. 3.4.3. Path and Shell Metacharacter Vulnerabilities
      4. 3.4.4. Temporary Files
      5. 3.4.5. Functions Unsuitable for Cryptographic Use
      6. 3.4.6. Forgeable Data
    5. 3.5. Untrusted Input
    6. 3.6. Result Verification
    7. 3.7. Data and Privilege Leakage
      1. 3.7.1. Data Leakage
      2. 3.7.2. Privilege Leakage
      3. 3.7.3. The Java Approach
      4. 3.7.4. Isolating Privileged Code
    8. 3.8. Trojan Horse
    9. 3.9. Tools
    10. Advice to Take Home
    11. Further Reading
  10. 4. Time Performance
    1. 4.1. Measurement Techniques
      1. 4.1.1. Workload Characterization
      2. 4.1.2. I/O-Bound Tasks
      3. 4.1.3. Kernel-Bound Tasks
      4. 4.1.4. CPU-Bound Tasks and Profiling Tools
    2. 4.2. Algorithm Complexity
    3. 4.3. Stand-Alone Code
    4. 4.4. Interacting with the Operating System
    5. 4.5. Interacting with Peripherals
    6. 4.6. Involuntary Interactions
    7. 4.7. Caching
      1. 4.7.1. A Simple System Call Cache
      2. 4.7.2. Replacement Strategies
      3. 4.7.3. Precomputing Results
    8. Advice to Take Home
    9. Further Reading
  11. 5. Space Performance
    1. 5.1. Data
      1. 5.1.1. Basic Data Types
      2. 5.1.2. Aggregate Data Types
        1. Arrays
        2. Structures
      3. 5.1.3. Alignment
      4. 5.1.4. Objects
    2. 5.2. Memory Organization
    3. 5.3. Memory Hierarchies
      1. 5.3.1. Main Memory and Its Caches
      2. 5.3.2. Disk Cache and Banked Memory
      3. 5.3.3. Swap Area and File-Based Disk Storage
    4. 5.4. The Process/Operating System Interface
      1. 5.4.1. Memory Allocation
      2. 5.4.2. Memory Mapping
      3. 5.4.3. Data Mapping
      4. 5.4.4. Code Mapping
      5. 5.4.5. Accessing Hardware Resources
      6. 5.4.6. Interprocess Communication
    5. 5.5. Heap Memory Management
      1. 5.5.1. Heap Fragmentation
      2. 5.5.2. Heap Profiling
      3. 5.5.3. Memory Leaks
      4. 5.5.4. Garbage Collection
    6. 5.6. Stack Memory Management
      1. 5.6.1. The Stack Frame
      2. 5.6.2. Stack Space
    7. 5.7. Code
      1. 5.7.1. Design Time
      2. 5.7.2. Coding Time
      3. 5.7.3. Build Time
    8. Advice to Take Home
    9. Further Reading
  12. 6. Portability
    1. 6.1. Operating Systems
    2. 6.2. Hardware and Processor Architectures
      1. 6.2.1. Data Type Properties
      2. 6.2.2. Data Storage
      3. 6.2.3. Machine-Specific Code
    3. 6.3. Compilers and Language Extensions
      1. 6.3.1. Compiler Bugs
        1. Nonstandard Extensions
        2. New Language Features
        3. Binary Compatibility
    4. 6.4. Graphical User Interfaces
    5. 6.5. Internationalization and Localization
      1. 6.5.1. Character Sets
      2. 6.5.2. Locale
      3. 6.5.3. Messages
    6. Advice to Take Home
    7. Further Reading
  13. 7. Maintainability
    1. 7.1. Measuring Maintainability
      1. 7.1.1. The Maintainability Index
        1. Applying Maintainability Metrics in Practice
      2. 7.1.2. Metrics for Object-Oriented Programs
        1. Weighted Methods per Class
        2. Depth of Inheritance Tree
        3. Number of Children
        4. Coupling Between Object Classes
        5. Response for a Class
        6. Lack of Cohesion in Methods
        7. Applying Object-Oriented Metrics in Practice
      3. 7.1.3. Dependency Metrics on Packages
    2. 7.2. Analyzability
      1. 7.2.1. Consistency
      2. 7.2.2. Expression Formatting
      3. 7.2.3. Statement Formatting
      4. 7.2.4. Naming Conventions
      5. 7.2.5. Statement-Level Comments
      6. 7.2.6. Versioning Comments
      7. 7.2.7. Visual Structure: Blocks and Indentation
      8. 7.2.8. Length of Expressions, Functions, and Methods
      9. 7.2.9. Control Structures
      10. 7.2.10. Boolean Expressions
      11. 7.2.11. Recognizability and Cohesion
      12. 7.2.12. Dependencies and Coupling
        1. Data Coupling
        2. Stamp Coupling
        3. Control Coupling
        4. Temporal Coupling
        5. Common Coupling
        6. External Coupling
        7. Content Coupling
      13. 7.2.13. Code Block Comments
      14. 7.2.14. Data Declaration Comments
      15. 7.2.15. Appropriate Identifier Names
      16. 7.2.16. Locality of Dependencies
      17. 7.2.17. Ambiguity
      18. 7.2.18. Reviewability
    3. 7.3. Changeability
      1. 7.3.1. Identification
        1. Intuitive Names
        2. The Role of Comments
        3. Polymorphic Abstraction
      2. 7.3.2. Separation
        1. When Coupling Interferes with Separability
        2. Increasing Separability Through Design Patterns
        3. Cohesive Design Abstractions
        4. Problems with Needless Repetition
        5. Hard-Coded Constants
        6. Comment Formatting
    4. 7.4. Stability
      1. 7.4.1. Encapsulation and Data Hiding
        1. Declare Variables within the Innermost Block that Uses Them
        2. Declare Class Members with the Least Visibility Required
        3. Encapsulate Groups of Related Classes Inside Modules
        4. Avoid Global Variables and Functions
        5. Use Components and Separate Processes to Isolate Large, Relatively Independent Subsystems
      2. 7.4.2. Data Abstraction
      3. 7.4.3. Type Checking
      4. 7.4.4. Compile-Time Assertions
      5. 7.4.5. Runtime Checks and Inspection-Time Assertions
    5. 7.5. Testability
      1. 7.5.1. Unit Testing
      2. 7.5.2. Integration Testing
        1. Test Harness
        2. Test Stub
      3. 7.5.3. System Testing
      4. 7.5.4. Test Coverage Analysis
      5. 7.5.5. Incidental Testing
        1. Assertions
        2. Defensive Coding
        3. Logging and Debug Messages
    6. 7.6. Effects of the Development Environment
      1. 7.6.1. Incremental Builds
      2. 7.6.2. Tuning Build Performance
    7. Advice to Take Home
    8. Further Reading
  14. 8. Floating-Point Arithmetic
    1. 8.1. Floating-Point Representation
      1. 8.1.1. Measuring Error
      2. 8.1.2. Rounding
      3. 8.1.3. Memory Format
      4. 8.1.4. Normalization and the Implied 1-Bit
      5. 8.1.5. Exponent Biasing
      6. 8.1.6. Negative Numbers
      7. 8.1.7. Denormal Numbers
      8. 8.1.8. Special Values
    2. 8.2. Rounding
    3. 8.3. Overflow
    4. 8.4. Underflow
    5. 8.5. Cancellation
    6. 8.6. Absorption
    7. 8.7. Invalid Operations
    8. Advice to Take Home
    9. Further Reading
  15. A. Source Code Credits
  16. Bibliography
  17. Epigraph Credits
  18. Colophon