Design for change and extensibility in Software Engineering - Time & Space Complexity
When designing software to handle change and grow over time, it is important to understand how the cost of making changes scales as the system grows.
We want to know how adding new features or modifying parts affects the work needed as the project size increases.
Analyze the time complexity of adding new features using a design that supports extensions.
class FeatureManager {
constructor() {
this.features = [];
}
addFeature(feature) {
this.features.push(feature);
}
runAll() {
for (const feature of this.features) {
feature.execute();
}
}
}
This code manages a list of features that can be added and run. It supports adding new features without changing existing code.
Look at the operations that repeat as the number of features grows.
- Primary operation: Looping through all features in
runAll()to execute them. - How many times: Once for each feature added, so the loop runs as many times as there are features.
As you add more features, the time to run all features grows proportionally.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 feature executions |
| 100 | 100 feature executions |
| 1000 | 1000 feature executions |
Pattern observation: The work grows directly with the number of features added.
Time Complexity: O(n)
This means the time to run all features grows linearly as you add more features.
[X] Wrong: "Adding more features won't affect performance much because each feature runs quickly."
[OK] Correct: Even if each feature is fast, running many features adds up, so total time grows with the number of features.
Understanding how design choices affect time complexity helps you build software that stays efficient as it grows, a skill valued in real projects and interviews.
"What if each feature called other features recursively? How would that affect the time complexity?"