In software engineering, software quality is an overall appreciation of software, based on many indicators. Completeness of functionality, correction and accuracy of results, reliability, fault tolerance, ease and flexibility of its use, simplicity, extensibility, compatibility and portability, ease of correction and transformation, performance, consistency and integrity of the information it contains are all quality factors.
Unlike hardware, the software is a product that does not have predictable reliability, moreover, it does not wear out over time. So, an anomaly occurs or does not occur in the execution of the software, the anomaly is present latently and may never occur. The quality of software depends entirely on its construction and the processes used for its development, so it is a central subject in software engineering. An overall assessment of quality takes into account both external factors, directly observable by the user, and internal factors, observable by engineers during code reviews or maintenance work.
Software quality problems, known since the 1960s, are also at the origin of software engineering, the science of software creation, including all the difficulties associated with it – respect for costs, deadlines, specifications and the level of quality. There are several certification standards for the quality management system in companies.
Please note that our present topic software quality control (QC) which is an engineering process, is different from software quality assurance (QA).
Software Quality Indicators
- Functional capacity: the ability of the functionalities of software to meet the explicit or implicit requirements and needs of users. This included accuracy, interoperability, compliance with standards and security; ease of use, which focuses on the effort required to learn how to handle the software. This included ease of understanding, learning and operation and robustness – incorrect use does not lead to malfunction.
- Reliability: the ability of software to render correct results regardless of operating conditions. This included fault tolerance – the ability of software to function even when disabled by the failure of a component.
- Performance: the ratio between the number of resources used (material means, time, personnel), and the number of results delivered. This included response time, throughput and scalability – the ability to maintain performance even under heavy use.
- Maintainability: This measures the effort required to correct or transform the software. This includes extensibility.
- Portability: The ability of software to operate in a hardware or software environment different from its initial environment. This is part of the ease of installation and configuration in the new environment.
An increase in functional capacity can harm performance, maintainability and reliability. While an increase in reliability, maintainability or availability has a positive impact on usability. In addition, an increase in maintainability can harm performance.
In software engineering, the factorization of data and code is the universal means of achieving quality. The factorization of the data results in the object model whose relational systematic correspondent is ideal when normalized. When data structures are standardized, they become non-redundant, therefore minimal in size, and do not cause any problem of inconsistency as long as the integrity resulting from their type and the referential integrity are ensured, constraints to which must be added “business rules” consisting of logical constraints involving several fields/attributes. This work at the data level allows in itself the reduction of the processing code exploiting this data. Performance does not suffer if queries are well organized.
Regarding code, factorization makes it possible to write similar statements only once, through a reasoned use of intermediate and local variables, loops, functions and procedures. This allows the maximum reduction of the size of the source code (without normal loss of readability) and results in the changes being as local as possible (therefore faster, and more reliable in terms of non-regression). An additional gain in source code reduction is provided by polymorphism and dynamic binding (which eliminate “referral procedures”) in object programming (these are generated by the compiler instead of having to be written explicitly by the programmer).
These factorizations bring out the right abstractions, the right structuring, and allow the best possible control of the integrity of the data and the proper execution of the treatments, whose functions, called in several points of the source code can become reused services, as much as the data which, being shared, are reused without duplication. This work allows an application to be “modular”. These modules are the services. Their interface is clear and without edge effect, the treatment they carry out becomes hidden (black box) for its customer modules.
The coupling between a module and its calling modules becomes as weak as possible, because only the values of parameters varying from one call to another are passed as an argument, the variables invariant between calls should ideally constitute attributes of a carrier-class, the function/module becoming a method (in a successful object programming). For the most critical modules, their flawless availability can be based on a physical instantiation redundancy strategy, or the contrary the maintenance of uniqueness but based on a hardware service managed autonomously by a dedicated team.
Abstraction aims to reduce the overall complexity of the software by reducing the number of modules and ensuring the essentials. It can also bring uniformity of the software that increases its usability by facilitating its learning and use.
The purpose of concealment is to completely separate the technical details of the software from its functionalities according to the black box principle, to improve its maintainability, portability and interoperability. The structuring of instructions and data makes visible in the source code the main lines of the organization of the instructions and information handled, which improves its maintainability and facilitates the detection of bugs.
Many programming languages support or even require the writing of source code according to the principles of structuring, modularity and concealment. This is the case for structured programming and object-oriented programming languages.