Every topic in this section fits somewhere in the software life cycle: requirements, then design, then implementation, then testing, then delivery, then maintenance. For each one, ask what artifact, decision, or quality issue the topic actually controls, and how change is managed once it happens. The single idea underlying the entire discipline: large software requires deliberate process, documentation, and verification, because complexity at scale cannot be handled reliably through coding skill alone.
A. Process Models and Requirements Engineering
Software engineering applies systematic methods to build and maintain software that meets requirements within cost, time, and quality constraints. Process models organize how this work actually proceeds: waterfall-like models emphasize staged, sequential progression through the life cycle; iterative and incremental models deliver working software in repeated cycles; agile approaches use short feedback loops, deliberately embrace evolving requirements, and emphasize close collaboration with stakeholders throughout. No single model is universally best — a safety-critical system may genuinely require more formal documentation and verification than a small experimental web prototype would, and choosing the right process model for the actual risk profile of a project is itself a core engineering judgment.
Requirements engineering discovers, documents, checks, and manages what stakeholders actually need from a system. Functional requirements describe the services or behaviour a system must provide; non-functional requirements describe qualities or constraints such as performance, security, usability, and reliability. Example: “a user can reset their password” is a functional requirement, while “the reset email must be sent within 30 seconds” is a non-functional (performance) requirement — the same feature area can generate both types of requirement, and conflating them leads to incomplete specifications. The standard activities here are elicitation (discovering needs), negotiation (resolving conflicting stakeholder demands), specification (writing requirements down clearly), validation (confirming they’re correct and complete), and change management (handling requirements that inevitably shift over the project’s life).
B. Design, Testing, and Maintenance
Design converts requirements into a structure developers can actually implement; architecture identifies a system’s major components and how they interact with each other. Good design seeks separation of concerns (each part handles one responsibility), cohesion (elements within a module belong together), low unnecessary coupling (modules don’t depend excessively on each other’s internals), clear interfaces, and long-term maintainability. Example: separating a system’s user interface, business logic, and data access into distinct layers makes each layer easier to change and test independently than mixing all three concerns together inside one module. Implementation is the stage that turns this design into actual code and integrated, working components.
Testing looks for failures and checks whether software actually meets its requirements — a genuinely different activity from proving correctness (covered in Section C). Standard testing levels include unit testing (verifying one function or component in isolation), integration testing (checking whether two or more modules communicate correctly together), system testing (testing the whole assembled system), and acceptance testing (confirming the system meets the customer’s actual needs). Verification asks “are we building the product right?” (does it meet its specification); validation asks “are we building the right product?” (does it meet the actual user need) — these are related but distinct questions. Delivery releases the finished system; maintenance and evolution change it afterward, classified as corrective (fixing bugs), adaptive (adjusting to a changed environment), perfective (improving performance or features), or preventive (reducing future maintenance risk) — and maintenance very often consumes the largest share of a system’s total lifecycle effort and cost, well beyond its original development.
C. Formal Specification, Quality Assurance, and Distributed/Aspect-Oriented Engineering
Formal specification uses mathematically precise descriptions of required system behaviour, while quality assurance is the broader planned set of activities that helps both processes and products meet quality requirements throughout development. Correctness proofs attempt to show that a program actually satisfies its specification under stated assumptions — this is fundamentally different from testing, which only samples a limited number of specific executions: a proof reasons mathematically about all cases covered by the model, while testing can only ever demonstrate the presence of bugs in the cases it happens to check, never their complete absence. Example: for a simple loop, a loop invariant (a condition proven to remain true before and after every single iteration) can help formally establish that a required property holds throughout the loop’s entire execution. Formal methods are genuinely valuable where the cost of failure is very high (such as safety-critical systems), but they can be expensive to apply and require specialized mathematical skill, which is why they are not used universally across all software.
Distributed software runs across multiple networked components rather than within a single machine, and this introduces genuinely new challenges: network failures, latency, concurrency, and data consistency across separate nodes. Example: a service that works flawlessly when tested locally can still fail when a real network call times out — robust distributed design has to handle this kind of failure explicitly rather than simply assuming the network always works. Aspect-oriented approaches isolate concerns that cut across many unrelated modules at once, such as logging or authorization, into a single reusable definition rather than scattering that same logic throughout the codebase. Project management, finally, plans people, scope, schedule, risk, and resources for a software effort, while process improvement measures and refines how development practices themselves can be made more predictable and effective over successive projects.
Software Engineering key takeaways: every activity here belongs to a stage of the life cycle — requirements, design, implementation, testing, delivery, maintenance — and understanding which stage a topic controls clarifies what it is actually for. No single process model fits every project; the right choice depends on the specific risk profile involved. Verification and validation ask different questions, and testing and formal proof provide fundamentally different kinds of assurance about correctness. Good design principles — separation of concerns, cohesion, low coupling — exist to make future change cheaper, which matters because maintenance typically dominates total lifecycle cost. Distributed systems introduce network-specific failure modes that must be designed for explicitly, not assumed away.
