The provided sources cover multiple aspects of software engineering, with a focus on architectural design, design and implementation, software testing, software evolution, as well as risk management and cost estimation in software projects.
Architectural Design (Chapter 6):
Architectural design is a critical step in the software engineering process. The sources emphasize the importance of having a clear and defined structure for software systems due to several advantages:
Stakeholder Communication: "The architecture may be used as a focus of discussion by system stakeholders."
System Analysis: A clear architecture allows analysis of the system’s ability to meet non-functional requirements.
Wide-Scale Reuse: "The architecture may be reusable across a range of systems." Software product line architectures can be developed.
Architectural models are used "as a way of facilitating discussion about the system design." Systems within the same domain often have similar structures, and application product lines can be built around a basic architecture with variations to meet customer requirements.
The sources also review common architectural patterns:
Repository Pattern: "All data in the system is managed in a central repository accessible by all system components. Components do not interact directly—only through the repository." Examples include Integrated Development Environments (IDEs). It is used when many components need shared data access. Drawbacks include a potential single point of failure, inefficient communication organization, and difficulty in distributing the repository.
Client-Server Pattern: "In the client-server architecture, system functionality is organized into services, with each service provided by a separate server. Clients are users of these services and access the servers to benefit from them." Used when data in a shared database needs to be accessed from multiple locations or when system load varies. The main advantage is the ability to distribute servers over a network.
Design and Implementation (Chapter 7):
Design and implementation are the phases in which an executable software system is developed. "Software design and implementation activities always overlap."
Software Design: A creative activity where "software components and their relationships are identified based on customer requirements."
Implementation: The process of "realizing the design as a program."
The sources mention the "build or buy" decision, where in many domains, "off-the-shelf (COTS) systems can be purchased and adapted to meet user requirements." This approach "can be cheaper and faster."
Object identification is a key process in design, depending on "the skill, experience, and domain knowledge of system designers." It is an iterative process that is "unlikely to be done correctly on the first try." There are various "approaches to object identification," including natural language descriptions, tangible domain objects, behavior, or scenario-based analysis.
"Design models show objects, object classes, and the relationships between them." There are static models describing structure and dynamic models describing interactions.
"A design pattern is a way of reusing abstract knowledge about a problem and its solution."
The sources define various levels of software reuse:
Abstraction Level: Reuse of knowledge about successful abstractions.
Object Level: Reuse of objects directly from a library.
Component Level: Reuse of collections of objects and classes.
System Level: Reuse of entire application systems.
In the context of open-source software, three major licensing models are mentioned:
GNU General Public License (GPL): A "reciprocal" license that requires making your software open source if using GPL-licensed code.
GNU Lesser General Public License (LGPL): A variation of GPL that allows linking with open-source code without requiring you to publish your own source.
Berkeley Standard Distribution (BSD) License: A non-reciprocal license that does not require publishing changes and allows inclusion in proprietary systems.
Software Testing (Chapter 8):
"The goal of testing is to show that the program does what it is supposed to and to discover defects before deployment." Testing uses synthetic data and checks the results for errors or distortions. "It can show the presence of errors, not their absence." Testing is part of the broader verification and validation process.
Goals of software testing include:
"Demonstrate to the developer and customer that the software meets its requirements."
"Discover cases where the software behavior is incorrect, undesirable, or deviates from specifications." "Defect testing" focuses on revealing unwanted behaviors.
The source differentiates between:
Verification: "Are we building the product right?" The software should conform to specifications.
Validation: "Are we building the right product?" The software should do what the user needs.
"Software inspections" are an important validation technique focusing on "analyzing" various system aspects before implementation. "Inspections do not require system execution, so they can be used before implementation." Applicable to any system representation (requirements, design, configuration data, test data, etc.). "They have proven effective in detecting software defects."
Advantages of inspections:
Do not mask other errors as testing might.
Incomplete versions of the system can be inspected at no additional cost.
Broader quality attributes can be considered, such as standard compliance, portability, and maintainability.
"Inspections and testing are complementary, not conflicting verification techniques." Both should be used. Inspections cannot verify conformance with real customer requirements or non-functional properties such as performance.
Testing stages include:
Development Testing: Conducted during development to find errors and defects, including:
Unit Testing: Testing individual components focusing on object or method functionality.
Component Testing: Combining several units to test component interfaces.
System Testing: Integrating some or all components to test the complete system with a focus on component interactions.
Release Testing: Conducted by a separate testing team on a complete system version before release to users.
User Testing: Conducted by users or potential users in their environment, including:
Alpha Testing: Conducted with the development team at the developer’s site.
Beta Testing: A release made available to users for experimentation and feedback.
Acceptance Testing: Customers test the system to decide if it's ready for acceptance and deployment.
"Unit testing is the process of testing individual components in isolation," and is a "defect testing" activity.
"Complete coverage testing of an object class includes testing all operations associated with the object and setting/querying all object attributes."
Interface testing aims to "detect errors caused by interface misuse or invalid assumptions about interfaces." Interface types include parameter interfaces, shared memory interfaces, procedural interfaces, and message-passing interfaces. Interface errors include "interface misuse," "interface misunderstanding," and "timing errors."
Stress testing is suggested for message-passing systems and changing component activation order in shared memory systems to identify interface errors.
"System testing during development involves integrating components to create a system version and testing the integrated system." Focuses on "testing interactions between components."
Test-driven development (TDD) is explained as an approach where automated tests are written before implementation. Tests are written for small units, run (and initially fail), then the function is implemented and tests are re-run until they pass.
Benefits of TDD include:
Code Coverage: Every piece of code has at least one test.
Regression Testing: Regression test suites are gradually built up.
Simplified Debugging: When a test fails, the source of the issue is clear.
System Documentation: The tests themselves document what the code is supposed to do.
"Regression testing is testing the system to ensure changes haven’t 'broken' previously working code."
Sources indicate that "interaction with the real user environment has a significant impact on the system's reliability, performance, usability, and robustness."
Software Evolution (Chapter 9):
"Software change is inevitable" due to factors like new requirements, changing work environments, fixing bugs, adding new hardware, improving performance and reliability. "A major issue for all organizations is implementing and managing change in existing software systems."
"System requirements are likely to change during development because the environment changes. Thus, the delivered system will not meet its requirements!" Systems are "tightly bound to their environment." "Systems must change to remain useful."
Types of Maintenance:
Fault Repair Maintenance: "Changing the system to fix errors in specification, design, or implementation."
Adaptive Maintenance: "Changing a system to adapt to a different operating environment" than the one it was originally deployed in.
Functional Maintenance: "Modifying the system to meet new requirements."
"Software maintenance costs usually exceed development costs" and are influenced by both technical and non-technical factors. "Maintenance costs increase with software aging."
"Predictions of change numbers require understanding the system-environment relationships." Tightly coupled systems need changes when the environment changes. Factors such as the number and complexity of system interfaces, the volatility of requirements, and the business processes using the system affect this relationship.
"Maintainability predictions can be made by assessing the system’s complexity."
Sources discuss strategies for dealing with legacy systems:
Keep the System As-Is: "Continue maintaining it normally."
System Refactoring: "Re-engineer the system to improve maintainability."
System Replacement: "Replace the system with a new one."
Strategy selection should be based on "system quality and business value." The sources provide categories of legacy systems based on quality and business value and suggest suitable strategies for each.
Project Management:
Software project management involves planning, risk identification, and overseeing development. "Project managers must create project plans, identify resources, and assign tasks to team members."
"Project management activities include creating a project plan, estimating costs and resources, scheduling, identifying and managing project risks, assigning personnel, and reporting."
"Risk management is a process relevant to project managers." "Project managers assess risks that may affect the project, monitor them, and take action when issues arise."
Risk Management Process:
Risk Identification: "Identify project, product, and business risks." May be done individually or collectively; common risk checklists may be used.
Risk Analysis: "Evaluate the probability and severity of each risk." Probability and consequences are classified.
Risk Planning: "Develop plans to avoid or reduce the risk impact." Includes avoidance, mitigation strategies, and contingency plans.
Risk Monitoring: "Track risks throughout the project."
Sources provide examples of various risk types (technical, human, organizational, requirements, estimation) and their possible impacts. They also offer examples of strategies for handling specific risks.
Cost Estimation:
"Algorithmic cost models" are used to estimate cost as a mathematical function of product, project, and process attributes. "Effort = A × Size^B × M." Size of the developed code is the most common cost estimation metric.
"The software system size cannot be precisely known until completion." Multiple factors affect final size, such as COTS usage, programming language, and system distribution. "The further development progresses, the more accurate size estimates become."
The COCOMO 2 model is mentioned as an "empirical model based on project experience."