Yesterday’s post, Software Reviews, demonstrated how to measure the quality of a software product based upon business needs. Before we can discuss how to review the software to measure its performance against the specified quality criteria we first must understand what makes a good quality program good in the first place. Today’s post will review foundational software principles that make possible the construction of solid software products.
The Value of Software Principles
To demonstrate the value of software principles I’d like to review how to patch a hole in the wall. First, you begin by cutting around the hole taking care to make a square that extends just above and below the hole and to the center of the joists to each side of the hole. Next you cut a piece of sheetrock that will fit into the hole using drywall screws to secure the sheet to the studs. Once the hole is covered the cracks between the new sheetrock and the original sheetrock must be taped and filled with mud. The mud is used to cover the cracks so that the wall appears seamless to the human eye.
When I first began mudding I naturally followed the line filling it in mud. I would use three coats as recommended but when finished the location of the cracks stood out like a sore thumb. You could see where the mud was applied to the cracks. Even with the lights off you could tell!
I hired a professional to resolve the problem and that’s when I learned what I did wrong. As my new, expensive friend began patching I noticed that after filling the cracks with the first coat, on the second coat he applied a circular motion. He didn’t follow the lines after the first coat. On the third application it was nearly a perfect circle. The mud couldn’t be seen because the circular pattern was much more difficult for the human eye to detect!
Often we write programs in the same way. We follow the crack not realizing that we are making the system fragile. The code works but the patch work can be easily seen. When mudding the wall the way that I applied the mud was just as important as the tools that I used. Likewise, in programming the way that we write software has just as much impact on the solution as the tool that we use.
Software Principles define how to use programming languages to construct a quality software product. The objective of these best practice concepts is to provide guidance on how to design a program so that it is inheritably efficient, flexible, extensible, secure, reliable, repeatable, and verifiable. Use of these best practices results in an application that is easier to transition to new support staff, easier to maintain, has fewer bugs and a greatly reduced cost of ownership over the life of the system.
All code patterns utilize one or more software principles while all code anti-patterns will break one or more principles. While designing and coding software special consideration should be given to these best practices. These concepts should always be used to measure the quality of a program during both the design review and the code review. A program should be immediately refactored when it is discovered that it violates any of these concepts.
I’m in no way implying that a perfect software solution can or should be created. Sometimes a database needs to be denormalized to make it more efficient and usable for real world scenarios. Likewise, sometimes an application’s design needs to be designed in a less than perfect manner to turn it into a feasable solution.
Design Pitfalls to Avoid
Coupling indicates the degree of integration between two entities. Tight coupling implies that a change to one component will have a rippling effect of changes to another component. Low coupling implies that a change to one component will have little effect on another. Highly coupled entities tend to be fragile.
Cohesion measures the degree of purpose in the relationship between two entities. Low cohesion implies that activities performed in a component are unrelated to it’s intended purpose. High cohesion implies that the work is specifically related to the purpose of the component and the entities it is consuming. Low cohesion results in work that is more costly to enhance.
In a nutshell programmers should strive to build programs that are loosely coupled but highly cohesive.
Inheritance vs Interface
Interestingly one of the programmers favorite tools violates the loose coupling, high cohesion guideline. Inheritance automatically infers tight coupling! However, when used correctly inheritance can be highly cohesive. So care must be taken to identify when inheritance truly benefits the system.
I prefer the use of interfaces to establish contracts between components. Interfaces encourage well thought out designs that are more likely to align with the loose coupling, tight cohesion guideline.
After implementing an interface a few times it becomes obvious where code is duplicated and could benefit from inheritance. Interface driven design helps drive out proper use of inheritance. It is after we have proven that inheritance offers value to the design that the code should be refactored.
So begin the design with interfaces. Allow the implementation of those interfaces to define when inheritance truly adds value to the code.
Software Principles
Without further ado here is a list of software principles that I have compiled from wikipedia.org.
Software Principle | Description | Consequences | How To Guidelines |
---|---|---|---|
Single Responsibility Principle | An entity should have only a single responsibility. |
|
Each entity (function, property, class, module) should have a single, clearly defined purpose. |
Command-query separation | The function performs an action or a query but not both. Asking a question should not change the answer. |
|
A routine should execute a specific action or get a specific value; never both. |
Separation of Concerns (SoC) | The analysis of a given problem to identify various tasks required to implement the specified functionality separating each task into its own entity. |
|
|
Law of Demeter (LoD)Principle of Least Knowledge | This principle encourages the design of loosely coupled components. |
|
|
Meyer’s Open/Closed principle | Entities should be open for extension but closed for modification. |
|
|
Polymorphic Open/Closed Principle | Entities should be open for extension but closed for modification. |
|
|
Design by Contract (DbC) | Interfaces should be formal, precise and verifiable. |
|
|
Option-operand Separation | Arguments for an entity should contain variables necessary to its function. Options should be managed in an external file. |
|
|
Interface Segregation Principle | Interfaces should be as small as possible so that the client isn’t forced to consume behaviors that it doesn’t need. |
|
|
Dependency Inversion Principle |
|
All high-level modules should be based on abstractions. |
Really like your post, is that ok if I use some of them for some internal development review process?
Comment by Irene Zhang — September 11, 2012 @ 12:26 pm |
Thank you for your comments. Please feel free to use as needed. Happy coding!
Comment by Larry Steinle — September 11, 2012 @ 12:41 pm |