
Introduction to Object-Oriented Design and Modelling
Lecture Notes
Important: These are primilary notes, you should always consult your own lecture notes and my lecture slides as the primary source. If you spot any issues in my lecture notes, please help me improve it (send a message on Discord). Would you like to make these notes better for everyone else? Please submit your own lecture notes and I will update this page (send me a message on Discord).
Introduction
The Paradox of Simple Rules and Complex Outcomes
Simple Rules and Complex Outcomes
The principle that simple computational rules can lead to complex software behavior is both intriguing and fundamental to understanding software development. A perfect analogy is the game of chess, where learning the basic moves opens up a universe of complex strategies and outcomes. This is akin to designing a bot to play chess, a task that seems straightforward but quickly escalates in complexity due to the vast number of possible game states.
This complexity arises from the interactions between simple steps, which become unpredictable as the software scales. A significant challenge here is the human limitation: we are capable of creating larger programs than we can fully comprehend, especially in large, changing teams. This highlights a critical aspect of software development: the necessity for systems that can evolve and adapt without becoming unwieldy.
Linux Kernel Complexity Over Time 1
The Linux Kernel serves as a prime example of this phenomenon. Over the years, its complexity has steadily increased, a trend that can be visualized through data analysis.
The growth in complexity is not just a reflection of added features but also the increasing challenges in managing such a vast and intricate codebase.
Firefox Browser Complexity Over Time 2
Similarly, the Firefox Browser has seen its complexity grow over time.

Adjustments to the data show a clear trend of escalating complexity, underscoring the challenges in browser development, from ensuring security to improving user experience.
You create software for a purpose (aka requirements)
The Challenge of Evolving Software Requirements
Software development is inherently dynamic, with requirements that evolve to meet changing user needs and market demands. For instance, an e-commerce app may initially focus on product listings but later need to integrate AI-based recommendations or augmented reality previews to stay competitive. This evolution demands flexible, adaptable designs that can accommodate such changes without major overhauls.
The Challenge of Evolving Software Requirements
To manage this, designs must be flexible and adaptable, allowing for the seamless integration of new features as the software evolves.
Designing for Complexity and Change
Design principles are crucial in managing software complexity and changing requirements. Object-oriented design, for example, offers techniques such as information hiding, interfaces, and polymorphism to promote loose coupling 3.
Good Software - Beyond Correctness
Good software transcends mere correctness. It embodies a balance between competing concerns like efficiency and maintainability, often requiring designers to make trade-offs based on the specific context of the project 4.
Design as an Art and Science
Software design merges the precision of science with the creativity of art. Consider the challenge of designing a music streaming application tailored for older adults. This task requires not just technical expertise but also a deep understanding of the user’s needs and preferences.

Granny’s Groovy Tunes
When designing “Granny’s Groovy Tunes,” two options emerge: Option 1: Simple, focusing on ease of use with basic functionalities, and Option 2: Feature-Rich, offering advanced features for those more acquainted with technology. Each option caters to different user needs, highlighting the art of making design choices that best serve the target audience.
How to design good software?
The journey of designing good software is marked by the need to adapt rapidly to new technologies and user expectations. Ride-sharing apps like Uber, Bolt, and Lyft exemplify this, constantly evolving to maintain a competitive edge. This adaptability is key to designing software that not only meets current needs but is also poised for future developments.
Uber’s Platform Evolution
Uber’s evolution from a luxury car service to a global platform offering a variety of services illustrates the dynamic nature
of software requirements and the importance of adaptability. The platform’s diversification, including UberX, UberPOOL, and UberEats, showcases how software can evolve to meet diverse consumer needs.
Market and Technological Changes
Adapting to market and technological changes is crucial for software success. Uber’s integration of AI and machine learning to optimize trip efficiency exemplifies how embracing technological advancements can enhance service delivery and user experience.
So how do Uber and other companies design good software?
The answer lies in the principles and practices of Software Engineering, a discipline dedicated to crafting high-quality software. It emphasizes a systematic approach to software development, focusing on reliability, efficiency, maintainability, and usability.
(Very Brief) Introduction to Software Engineering
Software Engineering is the application of engineering principles to software development. Its goal is to produce software that is not just functional but also reliable, efficient, and easy to maintain.
The Essence of Software Engineering
Software Engineering is about more than just coding; it involves understanding user needs, designing robust and scalable systems, and managing the software development process efficiently. It integrates aspects of computer science, project management, and engineering to create comprehensive software solutions.
Software Development Lifecycle
The software development lifecycle outlines the process of creating software, from requirements gathering to maintenance. The Waterfall Model is one such process, characterized by its sequential stages: Requirements, Design, Implementation, Verification, Deployment, and Maintenance. This structured approach ensures that each phase is completed before moving on to the next.
Waterfall Model Overview
The Waterfall Model emphasizes a methodical approach to software development, with each phase cascading into the next. This model provides a clear framework for project management and development, ensuring that all aspects of the software are thoroughly planned and executed.

Requirements Phase
The Requirements phase is foundational, providing a clear and detailed understanding of what the project aims to achieve. It involves activities like stakeholder identification, requirement gathering, and analysis, leading to a comprehensive Requirements Specification.
graph LR;
A(Start) --> B(Identify Stakeholders);
B --> C(Gather Requirements);
C --> D(Analyze Requirements);
D --> E(Requirements Specification);
E --> G(Validate Requirements);
G --> H(End);
style A fill:#808080,stroke:#333,stroke-width:4px
style B fill:#808080
style C fill:#808080
style D fill:#808080
style E fill:#808080
style G fill:#808080
style H fill:#808080,stroke:#333,stroke-width:4px
Design Phase
In the Design phase, the software’s architecture and user interface are conceptualized. This phase translates the requirements into a blueprint for the software, outlining how it will look and function.
graph LR;
E[Requirements Specification] --> A[Design];
A --> B[UI/UX Design];
B --> C[System Architecture];
C --> D[Design Document];
style A fill:#808080
style B fill:#808080
style C fill:#808080
style D fill:#808080
style E fill:#808080
Implementation Phase
The Implementation phase turns the design documents into a working application. It involves writing and compiling code based on the design specifications, transforming conceptual designs into functional software.
Verification Phase
Verification ensures that the software meets all requirements and design specifications. It includes testing the software to uncover any bugs and validate that it performs as intended.
graph LR;
A[Built Product] --> B[Verification];
B --> C[Validation];
C --> D[Testing];
style A fill:#808080
style B fill:#808080
style C fill:#808080
style D fill:#808080
Deployment and Maintenance Phases
Deployment makes the software available to end-users, while Maintenance involves ongoing support and updates based on user feedback. These phases are critical for the operational success and longevity of the software.
graph LR;
A[Verification] --> B[Prepare Release];
B --> C[Launch on Platforms];
C --> D[Monitor Performance];
style A fill:#808080
style B fill:#808080
style C fill:#808080
style D fill:#808080
graph LR;
A[Deployment] --> B[Provide Support];
B --> C[Implement Updates];
C --> D[Fix Bugs];
style A fill:#808080
style B fill:#808080
style C fill:#808080
style D fill:#808080
Designing Granny’s Groovy Tunes
Designing “Granny’s Groovy Tunes” involves a meticulous process from requirements gathering to maintenance. Each phase, from analyzing user needs to implementing and testing the software, is tailored to create a user-friendly music streaming application for older adults.
The Importance of Good Design
Good design is essential for successful software development. It not only ensures easier maintenance and scalability but also enhances user experience and performance. Conversely, poor design can lead to increased costs, complexity, and inefficiencies, making it difficult to adapt to new requirements or technologies.
The Role of Software Engineers
Software Engineers are the architects, responsible for analyzing user requirements, designing software solutions, and ensuring their quality and performance. Their role is crucial in bridging the gap between user needs and technological capabilities, crafting software that is not only functional but also reliable and user-friendly.
Quick Recap: Object-Oriented Programming (OOP)
As we prepare for a deeper dive into Object-Oriented Programming (OOP), it’s important to remember that OOP is a cornerstone of software engineering. It emphasizes objects as the central concept, facilitating the modeling of real-world entities and interactions in software. OOP’s principles, including encapsulation, abstraction, inheritance, and polymorphism, provide a powerful framework for developing flexible and maintainable software.
Introduction to Object-Oriented Analysis and Design (OOA/OOD)
OOA/OOD is a critical aspect of software development, focusing on analyzing problems and designing solutions using object-oriented concepts. This approach helps in identifying key entities and their interactions, laying the groundwork for effective software design.
Unified Modeling Language (UML)
UML is an indispensable tool in software design, offering a graphical language for specifying, visualizing, and documenting software systems. It provides a standardized approach to design, enhancing communication among stakeholders and reducing ambiguity in software development.
Design Patterns and Code Smells
Understanding design patterns and identifying code smells are essential skills for software developers. Design patterns offer reusable solutions to common problems, while recognizing code smells helps in detecting potential issues early. Both are crucial for writing good programs and avoiding pitfalls like those encountered by Knight Capital.
Footnotes
Source code: https://github.com/torvalds/linux↩︎
Source code: https://searchfox.org/mozilla-central/source↩︎
Loose coupling makes components easier to replace or reuse, reducing overall system complexity.↩︎
These attributes are commonly known as quality attributes, a concept further explored in Software Engineering.↩︎