Software Engineering

A comprehensive introduction to the principles, practices, and processes that enable teams to build reliable software at scale — from gathering requirements through long-term maintenance.

Course Overview

Software engineering is far more than writing code. It is the disciplined application of engineering principles to every phase of software creation — from understanding what stakeholders actually need, through designing and building a solution, to keeping that solution healthy for years after its first release.

This course provides the foundational toolkit that every practicing software engineer relies on: structured processes for eliciting requirements, systematic approaches to architectural design, disciplined testing strategies, and collaborative workflows that keep large teams productive. Students emerge with the ability to reason about software not just at the level of individual functions, but as living systems that must evolve gracefully over time.

Where this course fits. Software Engineering provides the broad foundation. Two companion courses on CodeLab go deeper in specialized directions: Antonio Mastropaolo’s Generative AI for Software Development explores how large language models are transforming SE practice, while Oscar Chaparro’s course examines the unique challenges of maintaining and evolving legacy systems.
6
Lifecycle Phases
435/535
Undergrad & Grad
7+
Core Topic Areas
W&M
William & Mary

The Software Engineering Lifecycle

At the heart of the course is the software development lifecycle (SDLC) — the structured sequence of phases that a project moves through from initial conception to eventual retirement. Understanding this lifecycle is what separates ad-hoc coding from engineering.

Requirements
Design
Implementation
Testing
Deployment
Maintenance

Each phase has its own techniques, deliverables, and failure modes. Requirements must be elicited carefully, or the wrong product gets built. Designs must balance flexibility with simplicity. Testing must be systematic, not just hopeful. And maintenance — often the longest phase — demands its own strategies for managing change without introducing regressions.

The course examines both traditional plan-driven models (such as Waterfall and the V-Model) and modern iterative approaches (Agile, Scrum), helping students understand when each is appropriate and how real teams often blend elements of both.

Requirements & Design

Building the right software starts with deeply understanding the problem. Requirements engineering is the process of discovering, documenting, and validating what a system should do — and, just as importantly, what it should not do.

Requirements Gathering

Students learn to work with stakeholders through interviews, surveys, and observation to extract both functional requirements (what the system must accomplish) and non-functional requirements (performance, security, usability constraints). Use-case analysis provides a structured way to capture interactions between users and the system.

Modeling and Design

Once requirements are understood, the course moves into design. UML diagrams — class diagrams, sequence diagrams, state machines — give teams a shared visual vocabulary for reasoning about system structure and behavior before writing a single line of code.

Architectural Patterns

Layered architectures, client-server, microservices, event-driven systems. Each pattern carries tradeoffs in scalability, maintainability, and complexity that students learn to evaluate.

Design Patterns

Proven solutions to recurring design problems: Observer, Strategy, Factory, Singleton, and others. Understanding when and why to apply them is as important as knowing their structure.

Version Control & Collaboration

Modern software is built by teams, and version control is the infrastructure that makes team-based development possible. Git has become the universal standard, but using it effectively requires understanding branching strategies, merge workflows, and the discipline of meaningful commit history.

Branching and Workflows

The course covers common branching models — feature branches, release branches, and trunk-based development — and helps students reason about which approach suits different team sizes and release cadences. Pull requests and code reviews are practiced as essential quality gates, not bureaucratic overhead.

Continuous Integration and Delivery

Automated build pipelines, continuous integration servers, and deployment automation close the loop between writing code and delivering working software. Students see how CI/CD practices catch integration problems early and reduce the risk of each release.

Connection to Mining Software Repositories. The version history, commit metadata, and code review discussions that accumulate in Git repositories are exactly the data sources explored in Mastropaolo’s MSR module. What this course teaches students to create, that module teaches them to analyze at scale.

Testing & Verification

Untested software is, at best, a hypothesis. The course gives students a rigorous foundation in verification and validation (V&V) — the dual questions of whether the system is built correctly and whether it is the correct system to build.

Levels of Testing

  • Unit testing — verifying individual functions or methods in isolation, typically with frameworks like JUnit or pytest.
  • Integration testing — checking that modules work together correctly when combined.
  • System testing — validating the complete, integrated system against requirements.
  • Acceptance testing — confirming the system meets stakeholder expectations in realistic conditions.

Test-Driven Development

TDD flips the traditional workflow: write a failing test first, then write just enough code to make it pass, then refactor. Students practice this rhythm and learn when it accelerates development and when it can become counterproductive.

Agile & Scrum

The Agile movement emerged from the recognition that software requirements are rarely stable and that rigid, plan-heavy processes often fail to deliver value quickly enough. The course explores the core values behind Agile thinking: responding to change, delivering working software frequently, and maintaining close collaboration with stakeholders.

Scrum in Practice

Scrum provides a lightweight framework for organizing iterative development. Students work through the mechanics of sprints, daily standups, sprint reviews, and retrospectives — learning not just the ceremony, but the reasoning behind each practice. Roles like Product Owner, Scrum Master, and Development Team are explored through hands-on project work.

Sprint Planning

Breaking work into manageable increments, estimating effort, and committing to a realistic sprint goal. The art of saying no to scope creep while staying responsive to real needs.

Retrospectives

The most important Scrum ceremony. Teams reflect on what went well, what did not, and what to change. Continuous improvement is not optional — it is the engine that makes Agile work.

Software Evolution & Maintenance

Most software spends far more time being maintained than being initially developed. The course introduces students to the realities of software aging: how systems accumulate technical debt, why seemingly small changes can have cascading effects, and what strategies (refactoring, re-engineering, wrapping) teams use to keep aging codebases viable.

Students examine Lehman’s laws of software evolution, which describe the forces that drive systems toward increasing complexity over their lifetime, and learn practical techniques for managing change without destabilizing a working system.

Going deeper. This course introduces the fundamentals of software maintenance and evolution. For students who want to specialize, Oscar Chaparro’s course on CodeLab dives much deeper into the research and practice of maintaining large-scale software systems.

Deep Learning for Software Engineering

The intersection of artificial intelligence and software engineering is one of the most rapidly evolving areas in computer science. This course provides an introduction to how machine learning — and particularly deep learning — is beginning to reshape everyday SE tasks: from code completion and automated bug detection to intelligent code review and test generation.

Students gain a conceptual understanding of how neural models treat source code as structured data, and why the massive repositories of code on platforms like GitHub have become valuable training corpora. The goal is not to turn students into ML researchers, but to make them informed practitioners who understand the capabilities and limitations of AI-assisted development tools.

The deep dive. This section provides a high-level orientation. Antonio Mastropaolo’s Generative AI for Software Development course on CodeLab offers a comprehensive, hands-on exploration of the models, techniques, and evaluation methods behind AI-powered software engineering.

About the Instructor

Denys Poshyvanyk is a Chancellor Professor of Computer Science and the Graduate Director in the Department of Computer Science at William & Mary. He leads the SEMERU research group (Software Evolution, Maintenance, and Energy Research Unit), which investigates problems at the intersection of software engineering, program comprehension, and machine learning.

His research has earned broad recognition across the field, including election as an ACM Fellow (2026) and an IEEE Fellow (2023), an NSF CAREER Award (2013), and seven best paper awards at top venues. His work spans software traceability, code search, mobile app analysis, and the application of deep learning techniques to software maintenance tasks.

More information is available on his faculty page and the SEMERU lab site.

Cross-Course Connections

CodeLab hosts three complementary perspectives on software engineering. Each course stands on its own, but together they form a comprehensive picture of how software is built, analyzed, and maintained in the age of AI.

Software Engineering

The broad foundation. Lifecycle processes, design, testing, collaboration, and project management. Taught by Denys Poshyvanyk.

Generative AI for SE

How large language models are transforming development practice — from code generation to automated evaluation. Taught by Antonio Mastropaolo. Explore modules →

Software Maintenance

The specialized discipline of understanding, evolving, and repairing existing systems at scale. Taught by Oscar Chaparro.

Students who take all three gain a rare combination: the engineering fundamentals to build well, the AI literacy to leverage modern tools, and the maintenance expertise to keep systems healthy over their entire lifespan.

← Back to

All Courses

Return to the full course listing on CodeLab.