1.4 Compare Software Development Methods
๐ Overview: Software development methodologies are frameworks that structure the development process. The three main approaches are Waterfall, Agile, and Lean.
Development Methods Comparison
graph TB
A[Software Development Methods] --> B[Waterfall]
A --> C[Agile]
A --> D[Lean]
B --> B1[Sequential Phases]
B --> B2[Heavy Documentation]
B --> B3[Fixed Requirements]
B --> B4[Long Release Cycles]
C --> C1[Iterative Development]
C --> C2[Customer Collaboration]
C --> C3[Adaptive Planning]
C --> C4[Short Sprints]
D --> D1[Eliminate Waste]
D --> D2[Continuous Improvement]
D --> D3[Fast Delivery]
D --> D4[Respect for People]
style A fill:#667eea,stroke:#764ba2,stroke-width:3px,color:#fff
style B fill:#ff6b6b,stroke:#c92a2a,color:#fff
style C fill:#51cf66,stroke:#2f9e44,color:#fff
style D fill:#339af0,stroke:#1864ab,color:#fff
Waterfall Model
graph TD
A[Requirements] --> B[Design]
B --> C[Implementation]
C --> D[Testing]
D --> E[Deployment]
E --> F[Maintenance]
style A fill:#667eea,color:#fff
style B fill:#667eea,color:#fff
style C fill:#667eea,color:#fff
style D fill:#667eea,color:#fff
style E fill:#667eea,color:#fff
style F fill:#667eea,color:#fff
๐ Waterfall
Sequential & Linear
- โ Pros:
- Clear structure
- Easy to understand
- Well-documented
- Works for fixed requirements
- โ Cons:
- Inflexible
- Late testing
- No customer feedback
- High risk
๐ Agile
Iterative & Incremental
- โ Pros:
- Flexible & adaptive
- Continuous feedback
- Fast delivery
- Customer collaboration
- โ Cons:
- Less predictable
- Requires discipline
- Documentation lighter
- Scope creep risk
โก Lean
Value-Focused & Efficient
- โ Pros:
- Waste elimination
- Fast time-to-market
- Cost-effective
- Continuous improvement
- โ Cons:
- Requires culture shift
- May sacrifice features
- Needs experienced team
- Measurement overhead
Agile Sprint Cycle
graph LR
A[Sprint Planning] --> B[Daily Standups]
B --> C[Development]
C --> D[Sprint Review]
D --> E[Sprint Retrospective]
E --> A
style A fill:#51cf66,stroke:#2f9e44,color:#fff
style B fill:#51cf66,stroke:#2f9e44,color:#fff
style C fill:#51cf66,stroke:#2f9e44,color:#fff
style D fill:#51cf66,stroke:#2f9e44,color:#fff
style E fill:#51cf66,stroke:#2f9e44,color:#fff
Detailed Comparison Table
| Aspect | Waterfall | Agile | Lean |
|---|---|---|---|
| Approach | Sequential phases | Iterative sprints | Continuous flow |
| Planning | Upfront & detailed | Adaptive & ongoing | Just-in-time |
| Requirements | Fixed at start | Evolving | Minimal viable |
| Customer Involvement | Beginning & end | Continuous | Frequent |
| Testing | After development | Throughout | Continuous |
| Delivery | Single release | Incremental releases | Continuous delivery |
| Best For | Fixed scope projects | Evolving projects | Startups, MVPs |
| Team Size | Any size | Small to medium | Small teams |
Agile Manifesto Values
๐ฅ Individuals over Processes
๐ป Working Software over Documentation
๐ค Customer Collaboration over Contracts
๐ Responding to Change over Plans
Lean Principles
1. Eliminate Waste
Remove anything that doesn't add value to the customer
2. Build Quality In
Prevent defects rather than finding them later
3. Create Knowledge
Learn continuously and share knowledge
4. Defer Commitment
Decide as late as possible with maximum information
5. Deliver Fast
Shorten cycle time and deliver quickly
6. Respect People
Empower the team and respect their expertise
๐ก Choosing the Right Method:
- Use Waterfall for: Well-defined projects, regulatory environments, fixed budgets
- Use Agile for: Complex projects, evolving requirements, frequent releases
- Use Lean for: Startups, MVPs, resource constraints, rapid innovation
- Many organizations use hybrid approaches combining elements from multiple methodologies
1.5 Benefits of Organizing Code
๐ Overview: Organizing code into functions, classes, and modules improves maintainability, reusability, and readability. It's a fundamental principle of software engineering.
Code Organization Hierarchy
graph TB
A[Application] --> B[Modules/Packages]
B --> C[Classes]
C --> D[Methods]
D --> E[Functions]
B --> B1[Separate files/folders]
C --> C1[Related data & behavior]
D --> D1[Class-specific operations]
E --> E1[Reusable operations]
style A fill:#667eea,stroke:#764ba2,stroke-width:3px,color:#fff
style B fill:#51cf66,stroke:#2f9e44,color:#fff
style C fill:#339af0,stroke:#1864ab,color:#fff
style D fill:#ff6b6b,stroke:#c92a2a,color:#fff
style E fill:#ffd43b,stroke:#fab005,color:#000
1. Functions/Methods
โ Benefits
- Reusability: Write once, use many times
- Modularity: Break down complex problems
- Readability: Named operations are self-documenting
- Testing: Easy to test individual functions
- Maintenance: Changes in one place
๐ Example: Without Functions
# Calculate area - repeated code length1 = 10 width1 = 5 area1 = length1 * width1 print(area1) length2 = 8 width2 = 4 area2 = length2 * width2 print(area2)
โ Example: With Functions
def calculate_area(length, width):
return length * width
# Reusable and clear
area1 = calculate_area(10, 5)
area2 = calculate_area(8, 4)
print(area1)
print(area2)
2. Classes
classDiagram
class NetworkDevice {
+String hostname
+String ip_address
+String status
+connect()
+disconnect()
+send_command(cmd)
}
class Router {
+List interfaces
+configure_ospf()
+show_routing_table()
}
class Switch {
+List vlans
+configure_vlan()
+show_mac_table()
}
NetworkDevice <|-- Router
NetworkDevice <|-- Switch
style NetworkDevice fill:#667eea,color:#fff
style Router fill:#51cf66,color:#fff
style Switch fill:#339af0,color:#fff
โ Class Benefits
- Encapsulation: Bundle data with methods
- Inheritance: Reuse and extend behavior
- Polymorphism: Same interface, different implementations
- Abstraction: Hide complex details
- Organization: Group related functionality
๐ Class Example
class NetworkDevice:
def __init__(self, hostname, ip):
self.hostname = hostname
self.ip = ip
self.status = "disconnected"
def connect(self):
self.status = "connected"
return f"Connected to {self.hostname}"
def get_info(self):
return {
"hostname": self.hostname,
"ip": self.ip,
"status": self.status
}
# Usage
router = NetworkDevice("R1", "192.168.1.1")
router.connect()
print(router.get_info())
3. Modules
graph TB
A[Application] --> B[network_utils.py]
A --> C[database.py]
A --> D[api_client.py]
A --> E[config.py]
B --> B1[connect_device]
B --> B2[send_command]
B --> B3[parse_output]
C --> C1[connect_db]
C --> C2[query]
C --> C3[insert]
D --> D1[get_request]
D --> D2[post_request]
E --> E1[load_config]
E --> E2[save_config]
style A fill:#667eea,color:#fff
style B fill:#51cf66,color:#fff
style C fill:#339af0,color:#fff
style D fill:#ff6b6b,color:#fff
style E fill:#ffd43b,color:#000
โ Module Benefits
- Separation of Concerns: Each module has a specific purpose
- Namespace: Avoid naming conflicts
- Reusability: Import and use in multiple projects
- Maintainability: Find and fix code easily
- Collaboration: Team members work on different modules
๐ Module Structure
# network_utils.py
def connect_device(ip, username, password):
# Connection logic
pass
def send_command(device, command):
# Command execution
pass
# main.py
import network_utils
device = network_utils.connect_device(
"192.168.1.1", "admin", "pass"
)
result = network_utils.send_command(
device, "show ip route"
)
Code Organization Principles
DRY - Don't Repeat Yourself
KISS - Keep It Simple, Stupid
YAGNI - You Ain't Gonna Need It
Single Responsibility Principle
Separation of Concerns
High Cohesion, Low Coupling
Complete Example: Well-Organized Code
# config.py
DATABASE_URL = "postgresql://localhost/mydb"
API_KEY = "your-api-key"
# database.py
import psycopg2
from config import DATABASE_URL
class Database:
def __init__(self):
self.conn = None
def connect(self):
self.conn = psycopg2.connect(DATABASE_URL)
def query(self, sql):
cursor = self.conn.cursor()
cursor.execute(sql)
return cursor.fetchall()
# api_client.py
import requests
from config import API_KEY
class APIClient:
def __init__(self, base_url):
self.base_url = base_url
self.headers = {"Authorization": f"Bearer {API_KEY}"}
def get(self, endpoint):
url = f"{self.base_url}/{endpoint}"
return requests.get(url, headers=self.headers)
# main.py
from database import Database
from api_client import APIClient
# Clean, organized, and maintainable!
db = Database()
db.connect()
results = db.query("SELECT * FROM devices")
api = APIClient("https://api.example.com")
response = api.get("devices/status")
๐ฏ Best Practices:
- Functions should do one thing and do it well
- Classes should represent real-world concepts
- Modules should have clear, single purposes
- Use meaningful names that describe purpose
- Keep functions and methods short (under 50 lines)
- Document your code with docstrings and comments
1.6 Common Design Patterns
๐จ Overview: Design patterns are reusable solutions to common software design problems. MVC and Observer are two of the most widely used patterns.
MVC Pattern (Model-View-Controller)
graph TB
U[User] --> V[View]
V --> C[Controller]
C --> M[Model]
M --> C
C --> V
V1[Presentation Layer
UI Components] --> V C1[Business Logic
User Input Handler] --> C M1[Data Layer
Database Access] --> M style U fill:#667eea,color:#fff style V fill:#51cf66,color:#fff style C fill:#339af0,color:#fff style M fill:#ff6b6b,color:#fff
UI Components] --> V C1[Business Logic
User Input Handler] --> C M1[Data Layer
Database Access] --> M style U fill:#667eea,color:#fff style V fill:#51cf66,color:#fff style C fill:#339af0,color:#fff style M fill:#ff6b6b,color:#fff
๐ฑ Model
Data & Business Logic
- Manages application data
- Contains business rules
- Notifies views of changes
- Database operations
- Independent of UI
๐๏ธ View
Presentation Layer
- Displays data to user
- UI components
- Receives updates from model
- Sends user input to controller
- No business logic
๐ฎ Controller
Application Logic
- Handles user input
- Updates model
- Selects view
- Mediates between M & V
- Application flow control
MVC Workflow
sequenceDiagram
participant U as User
participant V as View
participant C as Controller
participant M as Model
U->>V: 1. Interacts with UI
V->>C: 2. Sends user action
C->>M: 3. Updates data
M->>M: 4. Processes business logic
M-->>C: 5. Returns result
C->>V: 6. Updates view
V-->>U: 7. Displays updated UI
MVC Example Code
# Model - Data and business logic
class DeviceModel:
def __init__(self):
self.devices = []
def add_device(self, hostname, ip):
device = {"hostname": hostname, "ip": ip, "status": "active"}
self.devices.append(device)
return device
def get_all_devices(self):
return self.devices
def get_device(self, hostname):
return next((d for d in self.devices if d["hostname"] == hostname), None)
# View - Presentation
class DeviceView:
def display_devices(self, devices):
print("\\n=== Network Devices ===")
for device in devices:
print(f"{device['hostname']}: {device['ip']} - {device['status']}")
def display_device(self, device):
if device:
print(f"Device: {device['hostname']}")
print(f"IP: {device['ip']}")
print(f"Status: {device['status']}")
else:
print("Device not found")
# Controller - Application logic
class DeviceController:
def __init__(self):
self.model = DeviceModel()
self.view = DeviceView()
def add_device(self, hostname, ip):
device = self.model.add_device(hostname, ip)
print(f"Added device: {hostname}")
def show_all_devices(self):
devices = self.model.get_all_devices()
self.view.display_devices(devices)
def show_device(self, hostname):
device = self.model.get_device(hostname)
self.view.display_device(device)
# Usage
controller = DeviceController()
controller.add_device("Router1", "192.168.1.1")
controller.add_device("Switch1", "192.168.1.2")
controller.show_all_devices()
controller.show_device("Router1")
MVC Advantages
๐ Separation of Concerns
โป๏ธ Reusability
๐งช Easy Testing
๐ฅ Parallel Development
๐ง Maintainability
๐จ Multiple Views
Observer Pattern
graph TB
S[Subject/Observable] --> O1[Observer 1]
S --> O2[Observer 2]
S --> O3[Observer 3]
S --> S1[State Change]
S1 --> N[Notify All Observers]
N --> O1
N --> O2
N --> O3
O1 --> U1[Update]
O2 --> U2[Update]
O3 --> U3[Update]
style S fill:#667eea,color:#fff
style O1 fill:#51cf66,color:#fff
style O2 fill:#51cf66,color:#fff
style O3 fill:#51cf66,color:#fff
๐ก Subject (Observable)
- Maintains list of observers
- Provides methods to attach/detach observers
- Notifies observers of state changes
- Doesn't know observer details
๐๏ธ Observer
- Subscribes to subject
- Implements update interface
- Receives notifications
- Reacts to state changes
Observer Pattern Flow
sequenceDiagram
participant S as Subject
participant O1 as Observer 1
participant O2 as Observer 2
O1->>S: subscribe()
O2->>S: subscribe()
Note over S: State changes
S->>O1: notify()
S->>O2: notify()
O1->>O1: update()
O2->>O2: update()
Observer Example Code
# Observer Pattern Implementation
class NetworkMonitor:
"""Subject/Observable"""
def __init__(self):
self._observers = []
self._device_status = {}
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self, device, status):
for observer in self._observers:
observer.update(device, status)
def set_device_status(self, device, status):
self._device_status[device] = status
print(f"[Monitor] {device} status changed to {status}")
self.notify(device, status)
class EmailAlert:
"""Observer 1"""
def update(self, device, status):
if status == "down":
print(f"[Email] Alert! {device} is DOWN - sending email...")
class SMSAlert:
"""Observer 2"""
def update(self, device, status):
if status == "down":
print(f"[SMS] Alert! {device} is DOWN - sending SMS...")
class Logger:
"""Observer 3"""
def update(self, device, status):
print(f"[Logger] Logging: {device} - {status}")
# Usage
monitor = NetworkMonitor()
# Attach observers
email_alert = EmailAlert()
sms_alert = SMSAlert()
logger = Logger()
monitor.attach(email_alert)
monitor.attach(sms_alert)
monitor.attach(logger)
# State changes trigger notifications
monitor.set_device_status("Router1", "up")
print()
monitor.set_device_status("Switch1", "down")
Observer Pattern Advantages
๐ Loose Coupling
๐ข Broadcast Communication
๐ Dynamic Relationships
๐ Scalability
๐ฏ Event-Driven
โป๏ธ Reusability
When to Use Each Pattern
| Pattern | Use When | Examples |
|---|---|---|
| MVC | Building user interfaces with separate data and presentation | Web applications, Desktop GUIs, Mobile apps |
| Observer | Need to notify multiple objects about state changes | Event systems, Monitoring tools, Pub-Sub messaging |
๐ฏ Pattern Benefits Summary:
- MVC: Separates concerns, makes testing easier, enables multiple views of same data
- Observer: Enables loose coupling, supports broadcast communication, dynamic subscriptions
- Both patterns promote reusability, maintainability, and scalability
- Commonly used in frameworks (Django, React, Angular, Vue)
โ ๏ธ Considerations:
- MVC: Can be complex for simple applications, requires discipline to maintain separation
- Observer: Can cause performance issues with many observers, debugging can be harder
- Don't overuse patterns - use them when they solve a real problem
๐ Interactive Python Interpreter
๐ป Live Python Environment: Write and execute Python code directly in your browser! Practice functions, classes, and code organization concepts.
Sample Code Templates
โ๏ธ Python Code Editor
๐ค Output
โณ Loading Python interpreter...
โจ Features:
- Real-time Python execution in your browser
- Practice functions, classes, and OOP concepts
- Try MVC and Observer pattern examples
- Great for DEVASC exam preparation
- No installation required
โ ๏ธ Limitations:
- Cannot import external libraries
- No file system access
- Limited to basic Python features
Quick Reference
Supported Features
- โ Functions & Classes
- โ Inheritance
- โ Lists & Dictionaries
- โ Loops & Conditionals
- โ Print & String formatting
Keyboard Shortcuts
- Tab - Indent
- Ctrl+Enter - Run Code
- Arrow Keys - Navigate tabs