Tuesday, March 01, 2005

Software Quality

Lately I have been following a lot of discussions on software code quality. There seems to be a lack of consensus on what quality means. This is not very surprising, since quality is a very subjective term, it means different things to different people. Here's what it means to me:
I believe every software is created for a specific purpose. The purpose usually defines the forces that act on the software. Most common forces that usually act on any software from a bsiness perspective are:
1. Adaptability - How well will the software adapt to changes
2. Reliability - How often will the software crash
3. Timeliness - How fast can we ship the software
4. Economy - How much will the software cost
5. Performance - Does the software have quick turnaround times
6. Scalability - Will the software continue to be performant if the user base were to increase substantially
7. Usability - How intuitive is it to use the software

These business factors are usually achieved by the following technical factors:
1. Architecture (Assuming OO design)
a. Choice of classes and their responsibilities
b. Coupling between classes
c. Usage of appropriate design patterns
d. Avoiding known anti patterns

2. Code quality
a. Adherence to coding standards
b. Choice of loops and conditionals
c. Algorithms
d. Size of methods (how large are the methods?)
e. Clarity of comments

3. Test coverage
a. Coverage of unit tests
b. Coverage of functional tests
c. Stress tests (for multi-user software)

4. The overall development process
a. Is the development process ad hoc or is it well outlined?
b. If it is well outlined then is it effective?
c. Code reviews
d. Build frequency
e. Processes each developer must follow locally before check-ins

Now let's consider each business factor and its relation with the technical factors.
1. Architecture
Software adaptability is usually achieved by the right selection of classes and loose coupling between them. This assumes knowledge of what is likely to change. However if we do not know aspects of the system that are likely to change then we could make a matrix of things that we think might change and associate a probability with change case. We can then address the high probability changes in the architecture.
Use of appropriate design patterns will be very useful.
2. Code Quality
We often have to refactor existing code when dealing with changes in business requirements. Two things are involved here. Identifying the code to change and understanding the implications of the change. Choice of appropriate class and method names, keeping methods small and meaningful, and clear comments play an important role in helping us identify code that needs to be refactored. Clear interactions among methods (non-spaghetti code?) will help us identify the implications of the change.
3. Test Coverage
Having a solid test harness will give us immediate feedback of the implication of refactoring.
4. The Overall Process
Regular code reviews ensure code quality, and adequate test coverage.

1. Architecture
Architecture probably does not have an important role here.
2. Code Quality
Good coding practices like dealing with and recovering from Exceptions gracefully are very useful to ensure reliability.
3. Test Coverage
Adequate tests are very important to ensure reliability.
4. The overall design process
Again code reviews will help ensure adequate test coverage.

This is the tricky one. Let's say it is very important for a customer to deploy the software by a certain date and let us assume that the time is scarce. Before I write ahead, let me make it clear that making timeliness an important priority can be done only by sacrificing other factors. Whether the sacrifice is appropriate is discussed a few paragraphs ahead.
1. Architecture
Not overengineering the architecture will be useful. An overengineered architecture usually means more classes, and will result in a significantly greater effort on coding and writing test cases. In short do not plan for the future. Plan for the current scope, use best practices and go ahead.
2. Code Quality
We surely cannot achieve timeliness by skipping some methods. Assuming that we've got the write the code we've got to write, where can we save time? Perhaps in the thought process. Perhaps in commenting the code. I definiteky will not recommend saving time in the thought process. Commenting on the other hand is something where corners can be cut. Please do not wince at the thought of cutting corners. Atleast not here. We will discuss the concept very soon.
3. Test Coverage
We can produce software quickly if we write fewer test cases. But this has been known to cause more delays in the QA phase. However I sure there is a law of dimishing returns for test coverage - although I not sure where the curve starts flattening.
4. The Overall Process
Keeping the process light will defenitely help. Perhaps reducing the frequency of code reviews or even elliminating them might help.

1. Architecture
Is there any aspect in the architecture of a software that can help us achieve economy? Maybe this is slightly misplaced, but using open source frameworks or products may reduce costs. I say *may* reduce costs because we will first have to calculate the total cost of ownership of the open source software we intend to use before we can determine if it will really reduce costs. Some people may be thinking - but architecture should be generic - how did frameworks and open source products get here? Well from a practical perpective I am not sure if architecture can be truly generic. If we were making a web based application using Struts, then we will identify Action classes and ActionForm classes. The choice of these classes has been dictated by Struts. Were we using Turbine or Spring then we would have designed the application slightly differently. I strongly believe that the design of an application is infuenced by the choice of frameworks and other third party products.
Again keeping the architecture simple will help us reduce development costs.
2. Code Quality
Here economy translates into time spent on developing the software. The priciples we identified for timeliness apply here too.
3. Test Coverage
Here economy translates into time spent on developing the software. The priciples we identified for timeliness apply here too. Choice of open source testing frameworks might again help us. However it is important to evaluate their total cost of ownership first.
4. The Overall Process
Certain processes are heavy and also demand the use of expensive tools. I am not sure if there is any clear indication if using such processes and tools add value commensurate to the cost of the tools and other process elements. Again like in 'timeliness', using a light weight process with appropriate, but simple (and open source) tools can reduce the overall cost of developement.

1. Architecture
Here too I am not very sure if architecture plays a role. Perhaps it does. For example the choice of technology will determine performance. Using EJB's will be slower than using POJO's. But the speed can be enhanced by increasing the resources on the server. There are way too many factors that determine the performance of an application. Architecture cannot be linked with performance in any simplistic way.
2. Code Quality
Code quality is important for performance. We identified algorithms as part of code quality. Most applications have to iterate through object trees to produce an output. Apprpriate algorithms, and database queries play an important role in the overall performance of an application. Having said this I do agree with the widely held belief - "first make it work, then make it fast".
3. Test Coverage
Having appropriate stress tests will help us uncover areas which perform inadequaltely. Test suites will not elliminate performance problems, they will only help us identify them, which is better than the client identifying them.
4. The Overall Process
Again the overall process will contribute only in terms of ensuring proper test coverage. Code reviews might uncover obvious performance issues.