Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallGood software design starts with software that does the job people need, behaves dependably, and remains understandable as requirements change. Santiago Garcia’s seven-virtue framework offers a practical way to discuss those qualities and their trade-offs—not a formal standard or a replacement for requirements, testing, or established design methods.
What are the seven virtues of good software design?
Garcia presents the virtues in this order: effectiveness, robustness, maintainability, flexibility, reusability, scalability, and efficiency. The sequence reflects his argument about priorities, not a universally accepted ranking.
| Virtue | What it asks |
|---|---|
| Effectiveness | Does the software meet the user’s actual need? |
| Robustness | Does it handle invalid, missing, or unexpected conditions without uncontrolled failure? |
| Maintainability | Can developers understand, correct, and extend it? |
| Flexibility | Can it accommodate different uses or data without rigid assumptions? |
| Reusability | Can a capability be used by more than one program or interface? |
| Scalability | Can it handle increased throughput as the platform grows, within acceptable constraints? |
| Efficiency | Does it produce useful results with appropriate time and resource use? |
1. Effectiveness: solve the right problem
Effectiveness means the software does the job the user needs. It is the foundation in Garcia’s framework: fast, portable, or elegant software is still a failure if it does not serve its purpose.
Start with the requirements and the people or systems the software serves. A design review should ask whether the intended behavior is clear and whether the proposed design can deliver it. This keeps technical qualities in service of the outcome rather than treating them as ends in themselves.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →#1 Best Overall
2. Robustness: handle conditions beyond the happy path
Robust software responds predictably when data is missing, malformed, null, or inconsistent, and when other unexpected conditions arise. The goal is not to pretend that errors cannot happen; it is to avoid letting them produce uncontrolled failure.
Consider what the software should do when an input is absent or invalid, and make that behavior explicit. Robustness matters particularly at boundaries where data or assumptions come from outside the component. Defensive handling can improve reliability, but unnecessary layers of checks can also make code harder to understand, so target the cases that matter.
3. Maintainability: make future changes manageable
Maintainability is the ability to read, correct, and extend software without making every change risky. Garcia associates it with clear names, limited scope, reduced duplication, useful abstractions, and documentation.
Rank #2
These practices help developers see what a component does and where a change belongs. Abstractions are useful when they clarify responsibilities or reduce repeated work; they are not automatically helpful just because they make code more general. The test is whether a future reader can understand the design and modify it with confidence.
4. Flexibility: accommodate change without losing coherence
Flexible components can support different uses or data without being locked to a single rigid assumption. Interfaces and composition can help provide that flexibility, while keeping each component’s responsibilities clear.
More flexibility is not always better. Generality can weaken cohesion, and connections between components can become difficult to manage. Add variation where there is a real need or plausible change, rather than designing for every imagined future use.
Rank #3
5. Reusability: separate capability from a particular interface
Reusability means a core capability can serve more than one program or environment. Low coupling and clear interfaces make this easier. For example, separating a reusable core from a command-line front end can let another interface use the same underlying capability.
Reuse is not guaranteed by adding abstractions. A component tied to assumptions from its original environment may be difficult to reuse elsewhere. Keep environment-specific behavior at the edges when reuse is a genuine requirement, and compare the cost of separation with the value of sharing the capability.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
6. Scalability: account for growth and bottlenecks
Scalability concerns whether a system can increase throughput as its underlying platform grows while maintaining acceptable performance. Growth can expose bottlenecks, high memory use, and contention for heavily used resources.
Rank #4
Evaluate scalability against the system’s expected workload and platform constraints. A design that works at one scale may behave differently when demand increases; identifying the likely bottlenecks is more useful than assuming that additional platform capacity will solve them automatically.
7. Efficiency: use resources appropriately
Efficiency is the use of time, memory, and other resources to produce useful results. Garcia puts it last because optimizing too early can make design harder to understand and more error-prone, while an understandable system is easier to correct or optimize later.
That ordering is an argument, not a universal rule. If a system has strict performance requirements, resource limits, or a workload where latency is central, efficiency needs to be addressed as a requirement from the outset. Otherwise, avoid complexity for speculative gains and make optimization decisions in light of actual needs and constraints.
Best Value
How should teams prioritize the virtues?
Garcia’s ordering suggests first delivering the intended function and dependable behavior, then preserving the ability to understand and adapt the system, and then addressing reuse, growth, and resource efficiency. It is a useful starting point for discussion, not an empirically proven hierarchy. Priorities vary: a prototype, a short-lived tool, and a long-lived product do not necessarily need the same balance.
The virtues can pull in different directions. An abstraction might enable reuse while making a small program harder to understand; extra defensive behavior may improve reliability while adding complexity; generality can blur a component’s purpose; and optimization can reduce readability. State the project’s requirements and constraints before deciding which trade-offs to accept.
Compare designs against the same needs
When comparing two approaches, use the same requirements and workload for both. Assess whether each:
- Meets user needs.
- Handles invalid or unexpected input appropriately.
- Can be understood and changed without undue risk.
- Accommodates the additional uses the project actually expects.
- Can be reused across the environments that matter.
- Supports increased throughput within platform constraints.
- Uses time and other resources appropriately.
Then identify which of those dimensions are most important for this project. A design is not best in every context simply because it scores well on every virtue in the abstract.
Recommended Free Tools
How the virtues relate to established design techniques
Virtue lists help teams communicate about desirable qualities; they do not replace specific engineering methods. Industrial Logic makes this distinction about its own, different code-virtues framework: “This doesn’t replace mechanisms such as the SOLID principles or the 4 Rules of Simple Design, it merely helps us communicate clearly about the code we love.”
There is overlap between Garcia’s concerns and other design guidance. The California Department of Technology’s The Big Plan summarizes Unix design rules involving modularity, clarity, composition, separation, simplicity, transparency, robustness, and repairability. It states: “Developers should design for simplicity by looking for ways to break up program systems into small, straightforward cooperating pieces.” That guidance aligns with several virtues; it does not endorse Garcia’s exact list or its ordering.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

